added cli_rmdir and cli_mkdir
[kai/samba.git] / source3 / utils / torture.c
index f3d76e0ee2536006f3a30ff21eab4562ca9293cc..8711af3fe1ae2335ffa8c41bc5215420122e8db2 100644 (file)
@@ -25,8 +25,8 @@
 
 #include "includes.h"
 
-static struct cli_state cli;
 static fstring host, workgroup, share, password, username, myname;
+static int max_protocol = PROTOCOL_NT1;
 static char *sockops="";
 
 
@@ -45,62 +45,63 @@ static double end_timer()
 }
 
 
-static int open_connection(void)
+static BOOL open_connection(struct cli_state *c)
 {
-       if (!cli_initialise(&cli) || !cli_connect(&cli, host, NULL)) {
+       if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
                printf("Failed to connect with %s\n", host);
+               return False;
        }
 
-       if (!cli_session_request(&cli, host, 0x20, myname)) {
+       if (!cli_session_request(c, host, 0x20, myname)) {
                printf("%s rejected the session\n",host);
-               cli_shutdown(&cli);
-               return -1;
+               cli_shutdown(c);
+               return False;
        }
 
-       if (!cli_negprot(&cli)) {
-               printf("%s rejected the negprot (%s)\n",host, cli_errstr(&cli));
-               cli_shutdown(&cli);
-               return -1;
+       c->protocol = max_protocol;
+
+       if (!cli_negprot(c)) {
+               printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
+               cli_shutdown(c);
+               return False;
        }
 
-       if (!cli_session_setup(&cli, username, password, strlen(password),
+       if (!cli_session_setup(c, username, password, strlen(password),
                               "", 0, workgroup)) {
-               printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(&cli));
-               cli_shutdown(&cli);
-               return -1;
+               printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+               cli_shutdown(c);
+               return False;
        }
 
-       if (!cli_send_tconX(&cli, share, "A:", password, strlen(password)+1)) {
-               printf("%s refused tree connect (%s)\n", host, cli_errstr(&cli));
-               cli_shutdown(&cli);
-               return -1;
+       if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
+               printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
+               cli_shutdown(c);
+               return False;
        }
 
-       return 0;
+       return True;
 }
 
 
 
-static void close_connection(void)
+static void close_connection(struct cli_state *c)
 {
-       if (!cli_tdis(&cli)) {
-               printf("tdis failed (%s)\n", cli_errstr(&cli));
+       if (!cli_tdis(c)) {
+               printf("tdis failed (%s)\n", cli_errstr(c));
        }
 
-       cli_shutdown(&cli);
+       cli_shutdown(c);
 }
 
 
-
-
-static BOOL wait_lock(int fnum, uint32 offset, uint32 len)
+static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
 {
-       while (!cli_lock(&cli, fnum, offset, len, -1)) {
+       while (!cli_lock(c, fnum, offset, len, -1)) {
                int eclass, num;
-               cli_error(&cli, &eclass, &num);
+               cli_error(c, &eclass, &num);
                if (eclass != ERRDOS || num != ERRlock) {
                        printf("lock failed (%s)\n", 
-                              cli_errstr(&cli));
+                              cli_errstr(c));
                        return False;
                }
        }
@@ -108,7 +109,7 @@ static BOOL wait_lock(int fnum, uint32 offset, uint32 len)
 }
 
 
-static int rw_torture(int numops)
+static BOOL rw_torture(struct cli_state *c, int numops)
 {
        char *lockfname = "\\torture.lck";
        fstring fname;
@@ -117,13 +118,13 @@ static int rw_torture(int numops)
        int pid2, pid = getpid();
        int i;
 
-       fnum2 = cli_open(&cli, lockfname, O_RDWR | O_CREAT | O_EXCL, 
+       fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
                         DENY_NONE);
        if (fnum2 == -1)
-               fnum2 = cli_open(&cli, lockfname, O_RDWR, DENY_NONE);
+               fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
        if (fnum2 == -1) {
-               printf("open of %s failed (%s)\n", lockfname, cli_errstr(&cli));
-               return -1;
+               printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
+               return False;
        }
 
 
@@ -134,46 +135,49 @@ static int rw_torture(int numops)
                }
                sprintf(fname,"\\torture.%u", n);
 
-               if (!wait_lock(fnum2, n*sizeof(int), sizeof(int))) {
-                       return -1;
+               if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+                       return False;
                }
 
-               fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+               fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
                if (fnum == -1) {
-                       printf("open failed (%s)\n", cli_errstr(&cli));
+                       printf("open failed (%s)\n", cli_errstr(c));
                        break;
                }
 
-               if (cli_write(&cli, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
-                       printf("write failed (%s)\n", cli_errstr(&cli));
+               if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+                       printf("write failed (%s)\n", cli_errstr(c));
                }
 
                pid2 = 0;
 
-               if (cli_read(&cli, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
-                       printf("read failed (%s)\n", cli_errstr(&cli));
+               if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+                       printf("read failed (%s)\n", cli_errstr(c));
                }
 
                if (pid2 != pid) {
                        printf("data corruption!\n");
                }
 
-               if (!cli_close(&cli, fnum)) {
-                       printf("close failed (%s)\n", cli_errstr(&cli));
+               if (!cli_close(c, fnum)) {
+                       printf("close failed (%s)\n", cli_errstr(c));
                }
 
-               if (!cli_unlink(&cli, fname)) {
-                       printf("unlink failed (%s)\n", cli_errstr(&cli));
+               if (!cli_unlink(c, fname)) {
+                       printf("unlink failed (%s)\n", cli_errstr(c));
                }
 
-               if (!cli_unlock(&cli, fnum2, n*sizeof(int), sizeof(int), -1)) {
-                       printf("unlock failed (%s)\n", cli_errstr(&cli));
+               if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
+                       printf("unlock failed (%s)\n", cli_errstr(c));
                }
        }
 
+       cli_close(c, fnum2);
+       cli_unlink(c, lockfname);
+
        printf("%d\n", i);
 
-       return 0;
+       return True;
 }
 
 static void usage(void)
@@ -186,6 +190,7 @@ static void usage(void)
        printf("\t-W workgroup\n");
        printf("\t-o num_operations\n");
        printf("\t-O socket_options\n");
+       printf("\t-m maximum protocol\n");
        printf("\n");
 
        exit(1);
@@ -195,15 +200,595 @@ static void usage(void)
 
 static void run_torture(int numops)
 {
-       if (open_connection() == 0) {
+       static struct cli_state cli;
+
+       if (open_connection(&cli)) {
                cli_sockopt(&cli, sockops);
 
                printf("pid %d OK\n", getpid());
 
-               rw_torture(numops);
+               rw_torture(&cli, numops);
+
+               close_connection(&cli);
+       }
+}
+
+/*
+  This test checks for two things:
+
+  1) correct support for retaining locks over a close (ie. the server
+     must not use posix semantics)
+  2) support for lock timeouts
+ */
+static void run_locktest1(void)
+{
+       static struct cli_state cli1, cli2;
+       char *fname = "\\locktest.lck";
+       int fnum1, fnum2, fnum3;
+       time_t t1, t2;
+
+       if (!open_connection(&cli1) || !open_connection(&cli2)) {
+               return;
+       }
+       cli_sockopt(&cli1, sockops);
+       cli_sockopt(&cli2, sockops);
+
+       printf("starting locktest1\n");
+
+       cli_unlink(&cli1, fname);
+
+       fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+       if (fnum1 == -1) {
+               printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+               return;
+       }
+       fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+       if (fnum2 == -1) {
+               printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+               return;
+       }
+       fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+       if (fnum3 == -1) {
+               printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+               return;
+       }
+
+       if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
+               printf("lock1 failed (%s)\n", cli_errstr(&cli1));
+               return;
+       }
+
+
+       if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+               printf("lock2 succeeded! This is a locking bug\n");
+               return;
+       } else {
+               int eclass, num;
+               cli_error(&cli2, &eclass, &num);
+               if (eclass != ERRDOS || num != ERRlock) {
+                       printf("error should have been ERRDOS/ERRlock (%s)\n", 
+                              cli_errstr(&cli2));
+                       return;
+               }
+       }
+
+
+       printf("Testing lock timeouts\n");
+       t1 = time(NULL);
+       if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
+               printf("lock3 succeeded! This is a locking bug\n");
+               return;
+       } else {
+               int eclass, num;
+               cli_error(&cli2, &eclass, &num);
+               if (eclass != ERRDOS || num != ERRlock) {
+                       printf("error should have been ERRDOS/ERRlock (%s)\n", 
+                              cli_errstr(&cli2));
+                       return;
+               }
+       }
+       t2 = time(NULL);
+
+       if (t2 - t1 < 5) {
+               printf("error: This server appears not to support timed lock requests\n");
+       }
+
+       if (!cli_close(&cli1, fnum2)) {
+               printf("close1 failed (%s)\n", cli_errstr(&cli1));
+               return;
+       }
+
+       if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+               printf("lock4 succeeded! This is a locking bug\n");
+               return;
+       } else {
+               int eclass, num;
+               cli_error(&cli2, &eclass, &num);
+               if (eclass != ERRDOS || num != ERRlock) {
+                       printf("error should have been ERRDOS/ERRlock (%s)\n", 
+                              cli_errstr(&cli2));
+                       return;
+               }
+       }
+
+       if (!cli_close(&cli1, fnum1)) {
+               printf("close2 failed (%s)\n", cli_errstr(&cli1));
+               return;
+       }
+
+       if (!cli_close(&cli2, fnum3)) {
+               printf("close3 failed (%s)\n", cli_errstr(&cli2));
+               return;
+       }
+
+       if (!cli_unlink(&cli1, fname)) {
+               printf("unlink failed (%s)\n", cli_errstr(&cli1));
+               return;
+       }
+
+
+       close_connection(&cli1);
+       close_connection(&cli2);
+
+       printf("Passed locktest1\n");
+}
+
+
+/*
+  This test checks that 
+
+  1) the server supports multiple locking contexts on the one SMB
+  connection, distinguished by PID.  
 
-               close_connection();
+  2) the server correctly fails overlapping locks made by the same PID (this
+     goes against POSIX behaviour, which is why it is tricky to implement)
+
+  3) the server denies unlock requests by an incorrect client PID
+*/
+static void run_locktest2(void)
+{
+       static struct cli_state cli;
+       char *fname = "\\locktest.lck";
+       int fnum1, fnum2, fnum3;
+
+       if (!open_connection(&cli)) {
+               return;
+       }
+
+       cli_sockopt(&cli, sockops);
+
+       printf("starting locktest2\n");
+
+       cli_unlink(&cli, fname);
+
+       cli_setpid(&cli, 1);
+
+       fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+       if (fnum1 == -1) {
+               printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+               return;
+       }
+
+       fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+       if (fnum2 == -1) {
+               printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
+               return;
+       }
+
+       cli_setpid(&cli, 2);
+
+       fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+       if (fnum3 == -1) {
+               printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
+               return;
        }
+
+       cli_setpid(&cli, 1);
+
+       if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
+               printf("lock1 failed (%s)\n", cli_errstr(&cli));
+               return;
+       }
+
+       if (cli_lock(&cli, fnum2, 0, 4, 0)) {
+               printf("lock2 succeeded! This is a locking bug\n");
+       } else {
+               int eclass, num;
+               cli_error(&cli, &eclass, &num);
+               if (eclass != ERRDOS || num != ERRlock) {
+                       printf("error should have been ERRDOS/ERRlock (%s)\n", 
+                              cli_errstr(&cli));
+                       return;
+               }
+       }
+
+       cli_setpid(&cli, 2);
+
+       if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
+               printf("unlock1 succeeded! This is a locking bug\n");
+       }
+
+       if (cli_lock(&cli, fnum3, 0, 4, 0)) {
+               printf("lock3 succeeded! This is a locking bug\n");
+       } else {
+               int eclass, num;
+               cli_error(&cli, &eclass, &num);
+               if (eclass != ERRDOS || num != ERRlock) {
+                       printf("error should have been ERRDOS/ERRlock (%s)\n", 
+                              cli_errstr(&cli));
+                       return;
+               }
+       }
+
+       cli_setpid(&cli, 1);
+
+       if (!cli_close(&cli, fnum1)) {
+               printf("close1 failed (%s)\n", cli_errstr(&cli));
+               return;
+       }
+
+       if (!cli_close(&cli, fnum2)) {
+               printf("close2 failed (%s)\n", cli_errstr(&cli));
+               return;
+       }
+
+       if (!cli_close(&cli, fnum3)) {
+               printf("close3 failed (%s)\n", cli_errstr(&cli));
+               return;
+       }
+
+       close_connection(&cli);
+
+       printf("locktest2 finished\n");
+}
+
+
+/*
+  This test checks that 
+
+  1) the server supports the full offset range in lock requests
+*/
+static void run_locktest3(int numops)
+{
+       static struct cli_state cli1, cli2;
+       char *fname = "\\locktest.lck";
+       int fnum1, fnum2, i;
+       uint32 offset;
+
+#define NEXT_OFFSET offset += (~(uint32)0) / numops
+
+       if (!open_connection(&cli1) || !open_connection(&cli2)) {
+               return;
+       }
+       cli_sockopt(&cli1, sockops);
+       cli_sockopt(&cli2, sockops);
+
+       printf("starting locktest3\n");
+
+       cli_unlink(&cli1, fname);
+
+       fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+       if (fnum1 == -1) {
+               printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+               return;
+       }
+       fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+       if (fnum2 == -1) {
+               printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+               return;
+       }
+
+       for (offset=i=0;i<numops;i++) {
+               NEXT_OFFSET;
+               if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+                       printf("lock1 %d failed (%s)\n", 
+                              i,
+                              cli_errstr(&cli1));
+                       return;
+               }
+
+               if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+                       printf("lock2 %d failed (%s)\n", 
+                              i,
+                              cli_errstr(&cli1));
+                       return;
+               }
+       }
+
+       for (offset=i=0;i<numops;i++) {
+               NEXT_OFFSET;
+
+               if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
+                       printf("error: lock1 %d succeeded!\n", i);
+                       return;
+               }
+
+               if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
+                       printf("error: lock2 %d succeeded!\n", i);
+                       return;
+               }
+
+               if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+                       printf("error: lock3 %d succeeded!\n", i);
+                       return;
+               }
+
+               if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+                       printf("error: lock4 %d succeeded!\n", i);
+                       return;
+               }
+       }
+
+       for (offset=i=0;i<numops;i++) {
+               NEXT_OFFSET;
+
+               if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
+                       printf("unlock1 %d failed (%s)\n", 
+                              i,
+                              cli_errstr(&cli1));
+                       return;
+               }
+
+               if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
+                       printf("unlock2 %d failed (%s)\n", 
+                              i,
+                              cli_errstr(&cli1));
+                       return;
+               }
+       }
+
+       if (!cli_close(&cli1, fnum1)) {
+               printf("close1 failed (%s)\n", cli_errstr(&cli1));
+       }
+
+       if (!cli_close(&cli2, fnum2)) {
+               printf("close2 failed (%s)\n", cli_errstr(&cli2));
+       }
+
+       if (!cli_unlink(&cli1, fname)) {
+               printf("unlink failed (%s)\n", cli_errstr(&cli1));
+               return;
+       }
+
+       close_connection(&cli1);
+       close_connection(&cli2);
+
+       printf("finished locktest3\n");
+}
+
+
+/*
+  This test checks that 
+
+  1) the server does not allow an unlink on a file that is open
+*/
+static void run_unlinktest(void)
+{
+       static struct cli_state cli;
+       char *fname = "\\unlink.tst";
+       int fnum;
+
+       if (!open_connection(&cli)) {
+               return;
+       }
+
+       cli_sockopt(&cli, sockops);
+
+       printf("starting unlink test\n");
+
+       cli_unlink(&cli, fname);
+
+       cli_setpid(&cli, 1);
+
+       fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+       if (fnum == -1) {
+               printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+               return;
+       }
+
+       if (cli_unlink(&cli, fname)) {
+               printf("error: server allowed unlink on an open file\n");
+       }
+
+       cli_close(&cli, fnum);
+       cli_unlink(&cli, fname);
+
+       close_connection(&cli);
+
+       printf("unlink test finished\n");
+}
+
+
+
+static void browse_callback(char *sname, uint32 stype, char *comment)
+{
+       printf("\t%20.20s %08x %s\n", sname, stype, comment);
+}
+
+
+/*
+  This test checks the browse list code
+
+*/
+static void run_browsetest(void)
+{
+       static struct cli_state cli;
+
+       printf("starting browse test\n");
+
+       if (!open_connection(&cli)) {
+               return;
+       }
+
+       printf("domain list:\n");
+       cli_NetServerEnum(&cli, workgroup, 
+                         SV_TYPE_DOMAIN_ENUM,
+                         browse_callback);
+
+       printf("machine list:\n");
+       cli_NetServerEnum(&cli, workgroup, 
+                         SV_TYPE_ALL,
+                         browse_callback);
+
+       close_connection(&cli);
+
+       printf("browse test finished\n");
+}
+
+
+/*
+  This checks how the getatr calls works
+*/
+static void run_attrtest(void)
+{
+       static struct cli_state cli;
+       int fnum;
+       time_t t, t2;
+       char *fname = "\\attrib.tst";
+
+       printf("starting attrib test\n");
+
+       if (!open_connection(&cli)) {
+               return;
+       }
+
+       cli_unlink(&cli, fname);
+       fnum = cli_open(&cli, fname, 
+                       O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+       cli_close(&cli, fnum);
+       if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+               printf("getatr failed (%s)\n", cli_errstr(&cli));
+       }
+
+       if (abs(t - time(NULL)) > 2) {
+               printf("ERROR: SMBgetatr bug. time is %s",
+                      ctime(&t));
+               t = time(NULL);
+       }
+
+       t2 = t-60*60*24; /* 1 day ago */
+
+       if (!cli_setatr(&cli, fname, 0, t2)) {
+               printf("setatr failed (%s)\n", cli_errstr(&cli));
+       }
+
+       if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+               printf("getatr failed (%s)\n", cli_errstr(&cli));
+       }
+
+       if (t != t2) {
+               printf("ERROR: getatr/setatr bug. times are\n%s",
+                      ctime(&t));
+               printf("%s", ctime(&t2));
+       }
+
+       cli_unlink(&cli, fname);
+
+       close_connection(&cli);
+
+       printf("attrib test finished\n");
+}
+
+
+/*
+  This checks a couple of trans2 calls
+*/
+static void run_trans2test(void)
+{
+       static struct cli_state cli;
+       int fnum;
+       uint32 size;
+       time_t c_time, a_time, m_time, w_time, m_time2;
+       char *fname = "\\trans2.tst";
+       char *dname = "\\trans2";
+       char *fname2 = "\\trans2\\trans2.tst";
+
+       printf("starting trans2 test\n");
+
+       if (!open_connection(&cli)) {
+               return;
+       }
+
+       cli_unlink(&cli, fname);
+       fnum = cli_open(&cli, fname, 
+                       O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+       if (!cli_qfileinfo(&cli, fnum, &c_time, &a_time, &m_time, &size)) {
+               printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
+       }
+       cli_close(&cli, fnum);
+
+       sleep(2);
+
+       cli_unlink(&cli, fname);
+       fnum = cli_open(&cli, fname, 
+                       O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+       cli_close(&cli, fnum);
+
+       if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size)) {
+               printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
+       } else {
+               if (c_time != m_time) {
+                       printf("create time=%s", ctime(&c_time));
+                       printf("modify time=%s", ctime(&m_time));
+                       printf("This system appears to have sticky create times\n");
+               }
+               if (a_time % (60*60) == 0) {
+                       printf("access time=%s", ctime(&a_time));
+                       printf("This system appears to set a midnight access time\n");
+               }
+
+               if (abs(m_time - time(NULL)) > 60*60*24*7) {
+                       printf("ERROR: totally incorrect times - maybe word reversed?\n");
+               }
+       }
+
+
+       cli_unlink(&cli, fname);
+       fnum = cli_open(&cli, fname, 
+                       O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+       cli_close(&cli, fnum);
+       if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, 
+                           &w_time, &size)) {
+               printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+       } else {
+               if (w_time < 60*60*24*2) {
+                       printf("write time=%s", ctime(&w_time));
+                       printf("This system appears to set a initial 0 write time\n");
+               }
+       }
+
+       cli_unlink(&cli, fname);
+
+
+       /* check if the server updates the directory modification time
+           when creating a new file */
+       if (!cli_mkdir(&cli, dname)) {
+               printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
+       }
+       sleep(3);
+       if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, 
+                           &w_time, &size)) {
+               printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+       }
+
+       fnum = cli_open(&cli, fname2, 
+                       O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+       cli_write(&cli, fnum,  (char *)&fnum, 0, sizeof(fnum));
+       cli_close(&cli, fnum);
+       if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, 
+                           &w_time, &size)) {
+               printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+       } else {
+               if (m_time2 == m_time)
+                       printf("This system does not update directory modification times\n");
+       }
+       cli_unlink(&cli, fname2);
+       cli_rmdir(&cli, dname);
+
+
+       close_connection(&cli);
+
+       printf("trans2 test finished\n");
 }
 
 
@@ -269,11 +854,14 @@ static void create_procs(int nprocs, int numops)
        argv++;
 
 
-       while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:")) != EOF) {
+       while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
                switch (opt) {
                case 'W':
                        fstrcpy(workgroup,optarg);
                        break;
+               case 'm':
+                       max_protocol = interpret_protocol(optarg, max_protocol);
+                       break;
                case 'N':
                        nprocs = atoi(optarg);
                        break;
@@ -317,6 +905,14 @@ static void create_procs(int nprocs, int numops)
        create_procs(nprocs, numops);
        printf("rw_torture: %g secs\n", end_timer());
 
+       run_locktest1();
+       run_locktest2();
+       run_locktest3(numops);
+       run_unlinktest();
+       run_browsetest();
+       run_attrtest();
+       run_trans2test();
+
        return(0);
 }