r23779: Change from v2 or later to v3 or later.
[idra/samba.git] / source3 / torture / torture.c
index f26ebb49b30e4290690646883063b2b2ab9d48b3..b5c454a3a116707a45b5a482db37606d3a14ce46 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#define NO_SYSLOG
-
 #include "includes.h"
 
+extern char *optarg;
+extern int optind;
+
 static fstring host, workgroup, share, password, username, myname;
 static int max_protocol = PROTOCOL_NT1;
 static const char *sockops="TCP_NODELAY";
@@ -35,6 +36,8 @@ static BOOL use_oplocks;
 static BOOL use_level_II_oplocks;
 static const char *client_txt = "client_oplocks.txt";
 static BOOL use_kerberos;
+static fstring multishare_conn_fname;
+static BOOL use_multishare_conn = False;
 
 BOOL torture_showall = False;
 
@@ -43,14 +46,15 @@ static double create_procs(BOOL (*fn)(int), BOOL *result);
 
 static struct timeval tp1,tp2;
 
+
 void start_timer(void)
 {
-       gettimeofday(&tp1,NULL);
+       GetTimeOfDay(&tp1);
 }
 
 double end_timer(void)
 {
-       gettimeofday(&tp2,NULL);
+       GetTimeOfDay(&tp2);
        return((tp2.tv_sec - tp1.tv_sec) + 
               (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
 }
@@ -70,7 +74,7 @@ void *shm_setup(int size)
        int shmid;
        void *ret;
 
-       shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
+       shmid = shmget(IPC_PRIVATE, size, S_IRUSR | S_IWUSR);
        if (shmid == -1) {
                printf("can't get shared memory\n");
                exit(1);
@@ -93,28 +97,29 @@ void *shm_setup(int size)
 }
 
 
-static BOOL open_nbt_connection(struct cli_state *c)
+static struct cli_state *open_nbt_connection(void)
 {
        struct nmb_name called, calling;
        struct in_addr ip;
-
-       ZERO_STRUCTP(c);
+       struct cli_state *c;
+       NTSTATUS status;
 
        make_nmb_name(&calling, myname, 0x0);
        make_nmb_name(&called , host, 0x20);
 
         zero_ip(&ip);
 
-       if (!cli_initialise(c)) {
+       if (!(c = cli_initialise())) {
                printf("Failed initialize cli_struct to connect with %s\n", host);
-               return False;
+               return NULL;
        }
 
        c->port = port_to_use;
 
-       if (!cli_connect(c, host, &ip)) {
-               printf("Failed to connect with %s\n", host);
-               return False;
+       status = cli_connect(c, host, &ip);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) );
+               return NULL;
        }
 
        c->use_kerberos = use_kerberos;
@@ -128,9 +133,10 @@ static BOOL open_nbt_connection(struct cli_state *c)
                 * Well, that failed, try *SMBSERVER ... 
                 * However, we must reconnect as well ...
                 */
-               if (!cli_connect(c, host, &ip)) {
-                       printf("Failed to connect with %s\n", host);
-                       return False;
+               status = cli_connect(c, host, &ip);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) );
+                       return NULL;
                }
 
                make_nmb_name(&called, "*SMBSERVER", 0x20);
@@ -139,14 +145,74 @@ static BOOL open_nbt_connection(struct cli_state *c)
                        printf("We tried with a called name of %s & %s\n",
                                host, "*SMBSERVER");
                        cli_shutdown(c);
-                       return False;
+                       return NULL;
                }
        }
 
-       return True;
+       return c;
+}
+
+/* Insert a NULL at the first separator of the given path and return a pointer
+ * to the remainder of the string.
+ */
+static char *
+terminate_path_at_separator(char * path)
+{
+       char * p;
+
+       if (!path) {
+               return NULL;
+       }
+
+       if ((p = strchr_m(path, '/'))) {
+               *p = '\0';
+               return p + 1;
+       }
+
+       if ((p = strchr_m(path, '\\'))) {
+               *p = '\0';
+               return p + 1;
+       }
+       
+       /* No separator. */
+       return NULL;
 }
 
-BOOL torture_open_connection(struct cli_state **c)
+/*
+  parse a //server/share type UNC name
+*/
+BOOL smbcli_parse_unc(const char *unc_name, TALLOC_CTX *mem_ctx,
+                     char **hostname, char **sharename)
+{
+       char *p;
+
+       *hostname = *sharename = NULL;
+
+       if (strncmp(unc_name, "\\\\", 2) &&
+           strncmp(unc_name, "//", 2)) {
+               return False;
+       }
+
+       *hostname = talloc_strdup(mem_ctx, &unc_name[2]);
+       p = terminate_path_at_separator(*hostname);
+
+       if (p && *p) {
+               *sharename = talloc_strdup(mem_ctx, p);
+               terminate_path_at_separator(*sharename);
+       }
+
+       if (*hostname && *sharename) {
+               return True;
+       }
+
+       TALLOC_FREE(*hostname);
+       TALLOC_FREE(*sharename);
+       return False;
+}
+
+static BOOL torture_open_connection_share(struct cli_state **c,
+                                  const char *hostname, 
+                                  const char *sharename)
 {
        BOOL retry;
        int flags = 0;
@@ -154,13 +220,15 @@ BOOL torture_open_connection(struct cli_state **c)
 
        if (use_kerberos)
                flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
-       
+
        status = cli_full_connection(c, myname,
-                                    host, NULL, port_to_use, 
-                                    share, "?????", 
+                                    hostname, NULL, port_to_use, 
+                                    sharename, "?????", 
                                     username, workgroup, 
-                                    password, flags, &retry);
+                                    password, flags, Undefined, &retry);
        if (!NT_STATUS_IS_OK(status)) {
+               printf("failed to open share connection: //%s/%s port:%d - %s\n",
+                       hostname, sharename, port_to_use, nt_errstr(status));
                return False;
        }
 
@@ -171,6 +239,47 @@ BOOL torture_open_connection(struct cli_state **c)
        return True;
 }
 
+void torture_open_connection_free_unclist(char **unc_list)
+{
+       if (unc_list!=NULL)
+       {
+               SAFE_FREE(unc_list[0]);
+               SAFE_FREE(unc_list);
+       }
+}
+
+BOOL torture_open_connection(struct cli_state **c, int conn_index)
+{
+       char **unc_list = NULL;
+       int num_unc_names = 0;
+       BOOL result;
+
+       if (use_multishare_conn==True) {
+               char *h, *s;
+               unc_list = file_lines_load(multishare_conn_fname, &num_unc_names, 0);
+               if (!unc_list || num_unc_names <= 0) {
+                       printf("Failed to load unc names list from '%s'\n", multishare_conn_fname);
+                       exit(1);
+               }
+
+               if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
+                                     NULL, &h, &s)) {
+                       printf("Failed to parse UNC name %s\n",
+                              unc_list[conn_index % num_unc_names]);
+                       torture_open_connection_free_unclist(unc_list);
+                       exit(1);
+               }
+
+               result = torture_open_connection_share(c, h, s);
+
+               /* h, s were copied earlier */
+               torture_open_connection_free_unclist(unc_list);
+               return result;
+       }
+
+       return torture_open_connection_share(c, host, share);
+}
+
 BOOL torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid)
 {
        uint16 old_vuid = cli->vuid;
@@ -180,7 +289,10 @@ BOOL torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid)
 
        fstrcpy(old_user_name, cli->user_name);
        cli->vuid = 0;
-       ret = cli_session_setup(cli, username, password, passlen, password, passlen, workgroup);
+       ret = NT_STATUS_IS_OK(cli_session_setup(cli, username,
+                                               password, passlen,
+                                               password, passlen,
+                                               workgroup));
        *new_vuid = cli->vuid;
        cli->vuid = old_vuid;
        fstrcpy(cli->user_name, old_user_name);
@@ -207,16 +319,16 @@ static BOOL check_error(int line, struct cli_state *c,
                        uint8 eclass, uint32 ecode, NTSTATUS nterr)
 {
         if (cli_is_dos_error(c)) {
-                uint8 class;
+                uint8 cclass;
                 uint32 num;
 
                 /* Check DOS error */
 
-                cli_dos_error(c, &class, &num);
+                cli_dos_error(c, &cclass, &num);
 
-                if (eclass != class || ecode != num) {
+                if (eclass != cclass || ecode != num) {
                         printf("unexpected error code class=%d code=%d\n", 
-                               (int)class, (int)num);
+                               (int)cclass, (int)num);
                         printf(" expected %d/%d %s (line=%d)\n", 
                                (int)eclass, (int)ecode, nt_errstr(nterr), line);
                         return False;
@@ -260,6 +372,8 @@ static BOOL rw_torture(struct cli_state *c)
        char buf[1024];
        BOOL correct = True;
 
+       memset(buf, '\0', sizeof(buf));
+
        fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
                         DENY_NONE);
        if (fnum2 == -1)
@@ -389,7 +503,7 @@ static BOOL rw_torture3(struct cli_state *c, char *lockfname)
                {
                        fnum = cli_open(c, lockfname, O_RDONLY, 
                                         DENY_NONE);
-                       msleep(10);
+                       smb_msleep(10);
                }
                if (fnum == -1) {
                        printf("second open read-only of %s failed (%s)\n",
@@ -427,9 +541,9 @@ static BOOL rw_torture3(struct cli_state *c, char *lockfname)
                                                  sizeof(buf)-count);
                        if (sent < 0)
                        {
-                               printf("read failed offset:%d size:%d (%s)\n",
-                                               count, sizeof(buf)-count,
-                                               cli_errstr(c));
+                               printf("read failed offset:%d size:%ld (%s)\n",
+                                      count, (unsigned long)sizeof(buf)-count,
+                                      cli_errstr(c));
                                correct = False;
                                sent = 0;
                        }
@@ -438,8 +552,7 @@ static BOOL rw_torture3(struct cli_state *c, char *lockfname)
                                if (memcmp(buf_rd+count, buf+count, sent) != 0)
                                {
                                        printf("read/write compare failed\n");
-                                       printf("offset: %d req %d recvd %d\n",
-                                               count, sizeof(buf)-count, sent);
+                                       printf("offset: %d req %ld recvd %ld\n", count, (unsigned long)sizeof(buf)-count, (unsigned long)sent);
                                        correct = False;
                                        break;
                                }
@@ -462,8 +575,8 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
        int fnum1;
        int fnum2;
        int i;
-       uchar buf[131072];
-       uchar buf_rd[131072];
+       char buf[131072];
+       char buf_rd[131072];
        BOOL correct = True;
        ssize_t bytes_read;
 
@@ -494,7 +607,7 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
                        printf("%d\r", i); fflush(stdout);
                }
 
-               generate_random_buffer(buf, buf_size, False);
+               generate_random_buffer((unsigned char *)buf, buf_size);
 
                if (cli_write(c1, fnum1, 0, buf, 0, buf_size) != buf_size) {
                        printf("write failed (%s)\n", cli_errstr(c1));
@@ -504,7 +617,8 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
 
                if ((bytes_read = cli_read(c2, fnum2, buf_rd, 0, buf_size)) != buf_size) {
                        printf("read failed (%s)\n", cli_errstr(c2));
-                       printf("read %d, expected %d\n", bytes_read, buf_size); 
+                       printf("read %d, expected %ld\n", (int)bytes_read, 
+                              (unsigned long)buf_size); 
                        correct = False;
                        break;
                }
@@ -537,9 +651,9 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
 static BOOL run_readwritetest(int dummy)
 {
        static struct cli_state *cli1, *cli2;
-       BOOL test1, test2;
+       BOOL test1, test2 = False;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -590,11 +704,11 @@ static BOOL run_readwritelarge(int dummy)
        static struct cli_state *cli1;
        int fnum1;
        const char *lockfname = "\\large.dat";
-       size_t fsize;
+       SMB_OFF_T fsize;
        char buf[126*1024];
        BOOL correct = True;
  
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -620,9 +734,11 @@ static BOOL run_readwritelarge(int dummy)
        }
 
        if (fsize == sizeof(buf))
-               printf("readwritelarge test 1 succeeded (size = %x)\n", fsize);
+               printf("readwritelarge test 1 succeeded (size = %lx)\n", 
+                      (unsigned long)fsize);
        else {
-               printf("readwritelarge test 1 failed (size = %x)\n", fsize);
+               printf("readwritelarge test 1 failed (size = %lx)\n", 
+                      (unsigned long)fsize);
                correct = False;
        }
 
@@ -652,9 +768,11 @@ static BOOL run_readwritelarge(int dummy)
        }
 
        if (fsize == sizeof(buf))
-               printf("readwritelarge test 2 succeeded (size = %x)\n", fsize);
+               printf("readwritelarge test 2 succeeded (size = %lx)\n", 
+                      (unsigned long)fsize);
        else {
-               printf("readwritelarge test 2 failed (size = %x)\n", fsize);
+               printf("readwritelarge test 2 failed (size = %lx)\n", 
+                      (unsigned long)fsize);
                correct = False;
        }
 
@@ -693,7 +811,6 @@ static BOOL run_netbench(int client)
 {
        struct cli_state *cli;
        int i;
-       fstring fname;
        pstring line;
        char cname[20];
        FILE *f;
@@ -708,7 +825,7 @@ static BOOL run_netbench(int client)
 
        nb_setup(cli);
 
-       slprintf(cname,sizeof(fname), "client%d", client);
+       slprintf(cname,sizeof(cname)-1, "client%d", client);
 
        f = fopen(client_txt, "r");
 
@@ -822,7 +939,7 @@ static BOOL run_locktest1(int dummy)
        time_t t1, t2;
        unsigned lock_timeout;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -866,7 +983,7 @@ static BOOL run_locktest1(int dummy)
        lock_timeout = (1 + (random() % 20));
        printf("Testing lock timeout with timeout=%u\n", lock_timeout);
        t1 = time(NULL);
-       if (cli_lock(cli2, fnum3, 0, 4, lock_timeout * 500, WRITE_LOCK)) {
+       if (cli_lock(cli2, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)) {
                printf("lock3 succeeded! This is a locking bug\n");
                return False;
        } else {
@@ -937,7 +1054,9 @@ static BOOL run_tcon_test(int dummy)
        char buf[4];
        BOOL ret = True;
 
-       if (!torture_open_connection(&cli)) {
+       memset(buf, '\0', sizeof(buf));
+
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
        cli_sockopt(cli, sockops);
@@ -1039,7 +1158,7 @@ static BOOL run_tcon2_test(int dummy)
        char *service;
        NTSTATUS status;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
        cli_sockopt(cli, sockops);
@@ -1128,7 +1247,7 @@ static BOOL run_tcon_devtype_test(int dummy)
                                     host, NULL, port_to_use,
                                     NULL, NULL,
                                     username, workgroup,
-                                    password, flags, &retry);
+                                    password, flags, Undefined, &retry);
 
        if (!NT_STATUS_IS_OK(status)) {
                printf("could not open connection\n");
@@ -1192,7 +1311,7 @@ static BOOL run_locktest2(int dummy)
        int fnum1, fnum2, fnum3;
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -1331,7 +1450,7 @@ static BOOL run_locktest3(int dummy)
 
 #define NEXT_OFFSET offset += (~(uint32)0) / torture_numops
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -1455,7 +1574,7 @@ static BOOL run_locktest4(int dummy)
        char buf[1000];
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
 
@@ -1626,7 +1745,7 @@ static BOOL run_locktest5(int dummy)
        char buf[1000];
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
 
@@ -1749,7 +1868,7 @@ static BOOL run_locktest6(int dummy)
        int fnum;
        NTSTATUS status;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -1789,7 +1908,7 @@ static BOOL run_locktest7(int dummy)
        char buf[200];
        BOOL correct = False;
 
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
 
@@ -1925,7 +2044,7 @@ static BOOL run_fdpasstest(int dummy)
        int fnum1;
        pstring buf;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -1980,7 +2099,7 @@ static BOOL run_fdsesstest(int dummy)
        pstring buf;
        BOOL ret = True;
 
-       if (!torture_open_connection(&cli))
+       if (!torture_open_connection(&cli, 0))
                return False;
        cli_sockopt(cli, sockops);
 
@@ -2062,7 +2181,7 @@ static BOOL run_unlinktest(int dummy)
        int fnum;
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2107,7 +2226,7 @@ test how many open files this server supports on the one socket
 static BOOL run_maxfidtest(int dummy)
 {
        struct cli_state *cli;
-       const char *template = "\\maxfid.%d.%d";
+       const char *ftemplate = "\\maxfid.%d.%d";
        fstring fname;
        int fnums[0x11000], i;
        int retries=4;
@@ -2123,7 +2242,7 @@ static BOOL run_maxfidtest(int dummy)
        cli_sockopt(cli, sockops);
 
        for (i=0; i<0x11000; i++) {
-               slprintf(fname,sizeof(fname)-1,template, i,(int)getpid());
+               slprintf(fname,sizeof(fname)-1,ftemplate, i,(int)getpid());
                if ((fnums[i] = cli_open(cli, fname, 
                                        O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
                    -1) {
@@ -2139,7 +2258,7 @@ static BOOL run_maxfidtest(int dummy)
 
        printf("cleaning up\n");
        for (;i>=0;i--) {
-               slprintf(fname,sizeof(fname)-1,template, i,(int)getpid());
+               slprintf(fname,sizeof(fname)-1,ftemplate, i,(int)getpid());
                cli_close(cli, fnums[i]);
                if (!cli_unlink(cli, fname)) {
                        printf("unlink of %s failed (%s)\n", 
@@ -2170,20 +2289,20 @@ static void rand_buf(char *buf, int len)
 static BOOL run_negprot_nowait(int dummy)
 {
        int i;
-       static struct cli_state cli;
+       static struct cli_state *cli;
        BOOL correct = True;
 
        printf("starting negprot nowait test\n");
 
-       if (!open_nbt_connection(&cli)) {
+       if (!(cli = open_nbt_connection())) {
                return False;
        }
 
        for (i=0;i<50000;i++) {
-               cli_negprot_send(&cli);
+               cli_negprot_send(cli);
        }
 
-       if (!torture_close_connection(&cli)) {
+       if (!torture_close_connection(cli)) {
                correct = False;
        }
 
@@ -2198,7 +2317,7 @@ static BOOL run_randomipc(int dummy)
 {
        char *rparam = NULL;
        char *rdata = NULL;
-       int rdrcnt,rprcnt;
+       unsigned int rdrcnt,rprcnt;
        pstring param;
        int api, param_len, i;
        struct cli_state *cli;
@@ -2207,7 +2326,7 @@ static BOOL run_randomipc(int dummy)
 
        printf("starting random ipc test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2260,7 +2379,7 @@ static BOOL run_browsetest(int dummy)
 
        printf("starting browse test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2298,7 +2417,7 @@ static BOOL run_attrtest(int dummy)
 
        printf("starting attrib test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2356,8 +2475,9 @@ static BOOL run_trans2test(int dummy)
 {
        struct cli_state *cli;
        int fnum;
-       size_t size;
-       time_t c_time, a_time, m_time, w_time, m_time2;
+       SMB_OFF_T size;
+       time_t c_time, a_time, m_time;
+       struct timespec c_time_ts, a_time_ts, m_time_ts, w_time_ts, m_time2_ts;
        const char *fname = "\\trans2.tst";
        const char *dname = "\\trans2";
        const char *fname2 = "\\trans2\\trans2.tst";
@@ -2366,15 +2486,15 @@ static BOOL run_trans2test(int dummy)
 
        printf("starting trans2 test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
        cli_unlink(cli, fname);
        fnum = cli_open(cli, fname, 
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
-       if (!cli_qfileinfo(cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
-                          NULL, NULL)) {
+       if (!cli_qfileinfo(cli, fnum, NULL, &size, &c_time_ts, &a_time_ts, &w_time_ts,
+                          &m_time_ts, NULL)) {
                printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(cli));
                correct = False;
        }
@@ -2429,13 +2549,13 @@ static BOOL run_trans2test(int dummy)
        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, NULL, NULL)) {
+       if (!cli_qpathinfo2(cli, fname, &c_time_ts, &a_time_ts, &w_time_ts
+                           &m_time_ts, &size, NULL, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
                correct = False;
        } else {
-               if (w_time < 60*60*24*2) {
-                       printf("write time=%s", ctime(&w_time));
+               if (w_time_ts.tv_sec < 60*60*24*2) {
+                       printf("write time=%s", ctime(&w_time_ts.tv_sec));
                        printf("This system appears to set a initial 0 write time\n");
                        correct = False;
                }
@@ -2451,8 +2571,8 @@ static BOOL run_trans2test(int dummy)
                correct = False;
        }
        sleep(3);
-       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time, &a_time, &m_time
-                           &w_time, &size, NULL, NULL)) {
+       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time_ts, &a_time_ts, &w_time_ts
+                           &m_time_ts, &size, NULL, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
                correct = False;
        }
@@ -2461,12 +2581,13 @@ static BOOL run_trans2test(int dummy)
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
        cli_write(cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
        cli_close(cli, fnum);
-       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time, &a_time, &m_time2
-                           &w_time, &size, NULL, NULL)) {
+       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time_ts, &a_time_ts, &w_time_ts
+                           &m_time2_ts, &size, NULL, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
                correct = False;
        } else {
-               if (m_time2 == m_time) {
+               if (memcmp(&m_time_ts, &m_time2_ts, sizeof(struct timespec))
+                   == 0) {
                        printf("This system does not update directory modification times\n");
                        correct = False;
                }
@@ -2489,19 +2610,19 @@ static BOOL run_trans2test(int dummy)
 
 static BOOL new_trans(struct cli_state *pcli, int fnum, int level)
 {
-       char buf[4096];
+       char *buf = NULL;
+       uint32 len;
        BOOL correct = True;
 
-       memset(buf, 0xff, sizeof(buf));
-
-       if (!cli_qfileinfo_test(pcli, fnum, level, buf)) {
+       if (!cli_qfileinfo_test(pcli, fnum, level, &buf, &len)) {
                printf("ERROR: qfileinfo (%d) failed (%s)\n", level, cli_errstr(pcli));
                correct = False;
        } else {
-               printf("qfileinfo: level %d\n", level);
-               dump_data(0, buf, 256);
+               printf("qfileinfo: level %d, len = %u\n", level, len);
+               dump_data(0, (uint8 *)buf, len);
                printf("\n");
        }
+       SAFE_FREE(buf);
        return correct;
 }
 
@@ -2515,7 +2636,7 @@ static BOOL run_w2ktest(int dummy)
 
        printf("starting w2k test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2550,7 +2671,7 @@ static BOOL run_oplock1(int dummy)
 
        printf("starting oplock test 1\n");
 
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
 
@@ -2608,7 +2729,7 @@ static BOOL run_oplock2(int dummy)
 
        printf("starting oplock test 2\n");
 
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                use_level_II_oplocks = False;
                use_oplocks = saved_use_oplocks;
                return False;
@@ -2617,7 +2738,7 @@ static BOOL run_oplock2(int dummy)
        cli1->use_oplocks = True;
        cli1->use_level_II_oplocks = True;
 
-       if (!torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli2, 1)) {
                use_level_II_oplocks = False;
                use_oplocks = saved_use_oplocks;
                return False;
@@ -2662,9 +2783,10 @@ static BOOL run_oplock2(int dummy)
 
        sleep(2);
 
-       /* Ensure cli1 processes the break. */
+       /* Ensure cli1 processes the break. Empty file should always return 0
+        * bytes.  */
 
-       if (cli_read(cli1, fnum1, buf, 0, 4) != 4) {
+       if (cli_read(cli1, fnum1, buf, 0, 4) != 0) {
                printf("read on fnum1 failed (%s)\n", cli_errstr(cli1));
                correct = False;
        }
@@ -2750,7 +2872,7 @@ static BOOL run_oplock3(int dummy)
                /* Child code */
                use_oplocks = True;
                use_level_II_oplocks = True;
-               if (!torture_open_connection(&cli)) {
+               if (!torture_open_connection(&cli, 0)) {
                        *shared_correct = False;
                        exit(0);
                } 
@@ -2764,7 +2886,7 @@ static BOOL run_oplock3(int dummy)
        /* parent code */
        use_oplocks = True;
        use_level_II_oplocks = True;
-       if (!torture_open_connection(&cli)) { 
+       if (!torture_open_connection(&cli, 1)) { /* other is forked */
                return False;
        }
        cli_oplock_handler(cli, oplock3_handler);
@@ -2788,8 +2910,8 @@ static BOOL run_oplock3(int dummy)
  */
 static BOOL run_deletetest(int dummy)
 {
-       struct cli_state *cli1;
-       struct cli_state *cli2;
+       struct cli_state *cli1 = NULL;
+       struct cli_state *cli2 = NULL;
        const char *fname = "\\delete.file";
        int fnum1 = -1;
        int fnum2 = -1;
@@ -2797,7 +2919,7 @@ static BOOL run_deletetest(int dummy)
        
        printf("starting delete test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -2808,8 +2930,8 @@ static BOOL run_deletetest(int dummy)
        cli_setatr(cli1, fname, 0, 0);
        cli_unlink(cli1, fname);
        
-       fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL,
-                                  FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 
+       fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_ALL_ACCESS|DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL,
+                                  0, FILE_OVERWRITE_IF, 
                                   FILE_DELETE_ON_CLOSE, 0);
        
        if (fnum1 == -1) {
@@ -2817,7 +2939,18 @@ static BOOL run_deletetest(int dummy)
                correct = False;
                goto fail;
        }
-       
+
+#if 0 /* JRATEST */
+        {
+                uint32 *accinfo = NULL;
+                uint32 len;
+                cli_qfileinfo_test(cli1, fnum1, SMB_FILE_ACCESS_INFORMATION, (char **)&accinfo, &len);
+               if (accinfo)
+                       printf("access mode = 0x%lx\n", *accinfo);
+                SAFE_FREE(accinfo);
+        }
+#endif
+
        if (!cli_close(cli1, fnum1)) {
                printf("[1] close failed (%s)\n", cli_errstr(cli1));
                correct = False;
@@ -3100,7 +3233,7 @@ static BOOL run_deletetest(int dummy)
        cli_setatr(cli1, fname, 0, 0);
        cli_unlink(cli1, fname);
        
-       if (!torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli2, 1)) {
                printf("[8] failed to open second connection.\n");
                correct = False;
                goto fail;
@@ -3113,7 +3246,7 @@ static BOOL run_deletetest(int dummy)
                                   FILE_OVERWRITE_IF, 0, 0);
        
        if (fnum1 == -1) {
-               printf("[8] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+               printf("[8] open of %s failed (%s)\n", fname, cli_errstr(cli1));
                correct = False;
                goto fail;
        }
@@ -3123,7 +3256,7 @@ static BOOL run_deletetest(int dummy)
                                   FILE_OPEN, 0, 0);
        
        if (fnum2 == -1) {
-               printf("[8] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+               printf("[8] open 2 of %s failed (%s)\n", fname, cli_errstr(cli2));
                correct = False;
                goto fail;
        }
@@ -3190,6 +3323,49 @@ static BOOL run_deletetest(int dummy)
                correct = False;
        } else
                printf("tenth delete on close test succeeded.\n");
+
+       cli_setatr(cli1, fname, 0, 0);
+       cli_unlink(cli1, fname);
+
+       /* What error do we get when attempting to open a read-only file with
+          delete access ? */
+
+       /* Create a readonly file. */
+       fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_DATA|FILE_WRITE_DATA,
+                                  FILE_ATTRIBUTE_READONLY, FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0);
+       if (fnum1 == -1) {
+               printf("[11] open of %s failed (%s)\n", fname, cli_errstr(cli1));
+               correct = False;
+               goto fail;
+       }
+
+       if (!cli_close(cli1, fnum1)) {
+               printf("[11] close failed (%s)\n", cli_errstr(cli1));
+               correct = False;
+               goto fail;
+       }
+
+       /* Now try open for delete access. */
+       fnum1 = cli_nt_create_full(cli1, fname, 0, FILE_READ_ATTRIBUTES|DELETE_ACCESS,
+                                  0, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                                  FILE_OVERWRITE_IF, 0, 0);
+       
+       if (fnum1 != -1) {
+               printf("[11] open of %s succeeded should have been denied with ACCESS_DENIED!\n", fname);
+               cli_close(cli1, fnum1);
+               goto fail;
+               correct = False;
+       } else {
+               NTSTATUS nterr = cli_nt_error(cli1);
+               if (!NT_STATUS_EQUAL(nterr,NT_STATUS_ACCESS_DENIED)) {
+                       printf("[11] open of %s should have been denied with ACCESS_DENIED! Got error %s\n", fname, nt_errstr(nterr));
+                       goto fail;
+                       correct = False;
+               } else {
+                       printf("eleventh delete on close test succeeded.\n");
+               }
+       }
+       
        printf("finished delete test\n");
 
   fail:
@@ -3197,15 +3373,15 @@ static BOOL run_deletetest(int dummy)
         * intialized, because these functions don't handle
         * uninitialized connections. */
                
-       cli_close(cli1, fnum1);
-       cli_close(cli1, fnum2);
+       if (fnum1 != -1) cli_close(cli1, fnum1);
+       if (fnum2 != -1) cli_close(cli1, fnum2);
        cli_setatr(cli1, fname, 0, 0);
        cli_unlink(cli1, fname);
 
-       if (!torture_close_connection(cli1)) {
+       if (cli1 && !torture_close_connection(cli1)) {
                correct = False;
        }
-       if (!torture_close_connection(cli2)) {
+       if (cli2 && !torture_close_connection(cli2)) {
                correct = False;
        }
        return correct;
@@ -3224,7 +3400,7 @@ static BOOL run_properties(int dummy)
        
        ZERO_STRUCT(cli);
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
        
@@ -3272,7 +3448,7 @@ static BOOL run_xcopy(int dummy)
 
        printf("starting xcopy test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3315,7 +3491,7 @@ static BOOL run_rename(int dummy)
 
        printf("starting rename test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3330,9 +3506,9 @@ static BOOL run_rename(int dummy)
        }
 
        if (!cli_rename(cli1, fname, fname1)) {
-               printf("First rename failed (this is correct) - %s\n", cli_errstr(cli1));
+               printf("First rename failed (SHARE_READ) (this is correct) - %s\n", cli_errstr(cli1));
        } else {
-               printf("First rename succeeded - this should have failed !\n");
+               printf("First rename succeeded (SHARE_READ) - this should have failed !\n");
                correct = False;
        }
 
@@ -3356,10 +3532,10 @@ static BOOL run_rename(int dummy)
        }
 
        if (!cli_rename(cli1, fname, fname1)) {
-               printf("Second rename failed - this should have succeeded - %s\n", cli_errstr(cli1));
+               printf("Second rename failed (SHARE_DELETE | SHARE_READ) - this should have succeeded - %s\n", cli_errstr(cli1));
                correct = False;
        } else {
-               printf("Second rename succeeded\n");
+               printf("Second rename succeeded (SHARE_DELETE | SHARE_READ)\n");
        }
 
        if (!cli_close(cli1, fnum1)) {
@@ -3403,10 +3579,10 @@ static BOOL run_rename(int dummy)
 #endif
 
        if (!cli_rename(cli1, fname, fname1)) {
-               printf("Third rename failed - this should have succeeded - %s\n", cli_errstr(cli1));
+               printf("Third rename failed (SHARE_NONE) - this should have succeeded - %s\n", cli_errstr(cli1));
                correct = False;
        } else {
-               printf("Third rename succeeded\n");
+               printf("Third rename succeeded (SHARE_NONE)\n");
        }
 
        if (!cli_close(cli1, fnum1)) {
@@ -3417,6 +3593,75 @@ static BOOL run_rename(int dummy)
        cli_unlink(cli1, fname);
        cli_unlink(cli1, fname1);
 
+        /*----*/
+
+       fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0, 0);
+
+       if (fnum1 == -1) {
+               printf("Fourth open failed - %s\n", cli_errstr(cli1));
+               return False;
+       }
+
+       if (!cli_rename(cli1, fname, fname1)) {
+               printf("Fourth rename failed (SHARE_READ | SHARE_WRITE) (this is correct) - %s\n", cli_errstr(cli1));
+       } else {
+               printf("Fourth rename succeeded (SHARE_READ | SHARE_WRITE) - this should have failed !\n");
+               correct = False;
+       }
+
+       if (!cli_close(cli1, fnum1)) {
+               printf("close - 4 failed (%s)\n", cli_errstr(cli1));
+               return False;
+       }
+
+       cli_unlink(cli1, fname);
+       cli_unlink(cli1, fname1);
+
+        /*--*/
+
+       fnum1 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0, 0);
+
+       if (fnum1 == -1) {
+               printf("Fifth open failed - %s\n", cli_errstr(cli1));
+               return False;
+       }
+
+       if (!cli_rename(cli1, fname, fname1)) {
+               printf("Fifth rename failed (SHARE_READ | SHARE_WRITE | SHARE_DELETE) - this should have failed ! \n");
+               correct = False;
+       } else {
+               printf("Fifth rename succeeded (SHARE_READ | SHARE_WRITE | SHARE_DELETE) (this is correct) - %s\n", cli_errstr(cli1));
+       }
+
+        /*
+         * Now check if the first name still exists ...
+         */
+
+        /*fnum2 = cli_nt_create_full(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0, 0);
+
+        if (fnum2 == -1) {
+          printf("Opening original file after rename of open file fails: %s\n",
+              cli_errstr(cli1));
+        }
+        else {
+          printf("Opening original file after rename of open file works ...\n");
+          (void)cli_close(cli1, fnum2);
+          } */
+
+        /*--*/
+
+
+       if (!cli_close(cli1, fnum1)) {
+               printf("close - 5 failed (%s)\n", cli_errstr(cli1));
+               return False;
+       }
+
+       cli_unlink(cli1, fname);
+       cli_unlink(cli1, fname1);
+        
        if (!torture_close_connection(cli1)) {
                correct = False;
        }
@@ -3432,7 +3677,7 @@ static BOOL run_pipe_number(int dummy)
        int num_pipes = 0;
 
        printf("starting pipenumber test\n");
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
 
@@ -3446,6 +3691,7 @@ static BOOL run_pipe_number(int dummy)
                        break;
                }
                num_pipes++;
+               printf("\r%6d", num_pipes);
        }
 
        printf("pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
@@ -3463,13 +3709,13 @@ static BOOL run_opentest(int dummy)
        const char *fname = "\\readonly.file";
        int fnum1, fnum2;
        char buf[20];
-       size_t fsize;
+       SMB_OFF_T fsize;
        BOOL correct = True;
        char *tmp_path;
 
        printf("starting open test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3616,7 +3862,7 @@ static BOOL run_opentest(int dummy)
        
        /* Test the non-io opens... */
 
-       if (!torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli2, 1)) {
                return False;
        }
        
@@ -3917,7 +4163,7 @@ static BOOL run_openattrtest(int dummy)
 
        printf("starting open attr test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -4011,7 +4257,7 @@ static BOOL run_openattrtest(int dummy)
        return correct;
 }
 
-static void list_fn(file_info *finfo, const char *name, void *state)
+static void list_fn(const char *mnt, file_info *finfo, const char *name, void *state)
 {
        
 }
@@ -4029,7 +4275,7 @@ static BOOL run_dirtest(int dummy)
 
        printf("starting directory test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4071,7 +4317,7 @@ static BOOL run_dirtest(int dummy)
        return correct;
 }
 
-static void del_fn(file_info *finfo, const char *mask, void *state)
+static void del_fn(const char *mnt, file_info *finfo, const char *mask, void *state)
 {
        struct cli_state *pcli = (struct cli_state *)state;
        fstring fname;
@@ -4102,7 +4348,7 @@ BOOL torture_ioctl_test(int dummy)
        DATA_BLOB blob;
        NTSTATUS status;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4130,7 +4376,8 @@ BOOL torture_ioctl_test(int dummy)
                        status = cli_raw_ioctl(cli, fnum, code, &blob);
 
                        if (NT_STATUS_IS_OK(status)) {
-                               printf("ioctl 0x%x OK : %d bytes\n", code, blob.length);
+                               printf("ioctl 0x%x OK : %d bytes\n", (int)code,
+                                      (int)blob.length);
                                data_blob_free(&blob);
                        }
                }
@@ -4153,7 +4400,7 @@ BOOL torture_chkpath_test(int dummy)
        int fnum;
        BOOL ret;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4226,8 +4473,125 @@ BOOL torture_chkpath_test(int dummy)
        return ret;
 }
 
+static BOOL run_eatest(int dummy)
+{
+       static struct cli_state *cli;
+       const char *fname = "\\eatest.txt";
+       BOOL correct = True;
+       int fnum, i;
+       size_t num_eas;
+       struct ea_struct *ea_list = NULL;
+       TALLOC_CTX *mem_ctx = talloc_init("eatest");
+
+       printf("starting eatest\n");
+       
+       if (!torture_open_connection(&cli, 0)) {
+               talloc_destroy(mem_ctx);
+               return False;
+       }
+       
+       cli_unlink(cli, fname);
+       fnum = cli_nt_create_full(cli, fname, 0,
+                                  FIRST_DESIRED_ACCESS, FILE_ATTRIBUTE_ARCHIVE,
+                                  FILE_SHARE_NONE, FILE_OVERWRITE_IF, 
+                                  0x4044, 0);
+
+       if (fnum == -1) {
+               printf("open failed - %s\n", cli_errstr(cli));
+               talloc_destroy(mem_ctx);
+               return False;
+       }
+
+       for (i = 0; i < 10; i++) {
+               fstring ea_name, ea_val;
+
+               slprintf(ea_name, sizeof(ea_name), "EA_%d", i);
+               memset(ea_val, (char)i+1, i+1);
+               if (!cli_set_ea_fnum(cli, fnum, ea_name, ea_val, i+1)) {
+                       printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+                       talloc_destroy(mem_ctx);
+                       return False;
+               }
+       }
+       
+       cli_close(cli, fnum);
+       for (i = 0; i < 10; i++) {
+               fstring ea_name, ea_val;
+
+               slprintf(ea_name, sizeof(ea_name), "EA_%d", i+10);
+               memset(ea_val, (char)i+1, i+1);
+               if (!cli_set_ea_path(cli, fname, ea_name, ea_val, i+1)) {
+                       printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+                       talloc_destroy(mem_ctx);
+                       return False;
+               }
+       }
+       
+       if (!cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)) {
+               printf("ea_get list failed - %s\n", cli_errstr(cli));
+               correct = False;
+       }
+
+       printf("num_eas = %d\n", (int)num_eas);
+
+       if (num_eas != 20) {
+               printf("Should be 20 EA's stored... failing.\n");
+               correct = False;
+       }
+
+       for (i = 0; i < num_eas; i++) {
+               printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
+               dump_data(0, ea_list[i].value.data,
+                         ea_list[i].value.length);
+       }
+
+       /* Setting EA's to zero length deletes them. Test this */
+       printf("Now deleting all EA's - case indepenent....\n");
+
+#if 1
+       cli_set_ea_path(cli, fname, "", "", 0);
+#else
+       for (i = 0; i < 20; i++) {
+               fstring ea_name;
+               slprintf(ea_name, sizeof(ea_name), "ea_%d", i);
+               if (!cli_set_ea_path(cli, fname, ea_name, "", 0)) {
+                       printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+                       talloc_destroy(mem_ctx);
+                       return False;
+               }
+       }
+#endif
+
+       if (!cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)) {
+               printf("ea_get list failed - %s\n", cli_errstr(cli));
+               correct = False;
+       }
+
+       printf("num_eas = %d\n", (int)num_eas);
+       for (i = 0; i < num_eas; i++) {
+               printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
+               dump_data(0, ea_list[i].value.data,
+                         ea_list[i].value.length);
+       }
+
+       if (num_eas != 0) {
+               printf("deleting EA's failed.\n");
+               correct = False;
+       }
 
+       /* Try and delete a non existant EA. */
+       if (!cli_set_ea_path(cli, fname, "foo", "", 0)) {
+               printf("deleting non-existant EA 'foo' should succeed. %s\n", cli_errstr(cli));
+               correct = False;
+       }
 
+       talloc_destroy(mem_ctx);
+       if (!torture_close_connection(cli)) {
+               correct = False;
+       }
+       
+       return correct;
+}
 
 static BOOL run_dirtest1(int dummy)
 {
@@ -4238,7 +4602,7 @@ static BOOL run_dirtest1(int dummy)
 
        printf("starting directory test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4312,8 +4676,8 @@ static BOOL run_dirtest1(int dummy)
 
 static BOOL run_error_map_extract(int dummy) {
        
-       static struct cli_state c_dos;
-       static struct cli_state c_nt;
+       static struct cli_state *c_dos;
+       static struct cli_state *c_nt;
 
        uint32 error;
 
@@ -4326,81 +4690,81 @@ static BOOL run_error_map_extract(int dummy) {
 
        /* NT-Error connection */
 
-       if (!open_nbt_connection(&c_nt)) {
+       if (!(c_nt = open_nbt_connection())) {
                return False;
        }
 
-       c_nt.use_spnego = False;
+       c_nt->use_spnego = False;
 
-       if (!cli_negprot(&c_nt)) {
-               printf("%s rejected the NT-error negprot (%s)\n",host, cli_errstr(&c_nt));
-               cli_shutdown(&c_nt);
+       if (!cli_negprot(c_nt)) {
+               printf("%s rejected the NT-error negprot (%s)\n",host, cli_errstr(c_nt));
+               cli_shutdown(c_nt);
                return False;
        }
 
-       if (!cli_session_setup(&c_nt, "", "", 0, "", 0,
-                              workgroup)) {
-               printf("%s rejected the NT-error initial session setup (%s)\n",host, cli_errstr(&c_nt));
+       if (!NT_STATUS_IS_OK(cli_session_setup(c_nt, "", "", 0, "", 0,
+                                              workgroup))) {
+               printf("%s rejected the NT-error initial session setup (%s)\n",host, cli_errstr(c_nt));
                return False;
        }
 
        /* DOS-Error connection */
 
-       if (!open_nbt_connection(&c_dos)) {
+       if (!(c_dos = open_nbt_connection())) {
                return False;
        }
 
-       c_dos.use_spnego = False;
-       c_dos.force_dos_errors = True;
+       c_dos->use_spnego = False;
+       c_dos->force_dos_errors = True;
 
-       if (!cli_negprot(&c_dos)) {
-               printf("%s rejected the DOS-error negprot (%s)\n",host, cli_errstr(&c_dos));
-               cli_shutdown(&c_dos);
+       if (!cli_negprot(c_dos)) {
+               printf("%s rejected the DOS-error negprot (%s)\n",host, cli_errstr(c_dos));
+               cli_shutdown(c_dos);
                return False;
        }
 
-       if (!cli_session_setup(&c_dos, "", "", 0, "", 0,
-                              workgroup)) {
-               printf("%s rejected the DOS-error initial session setup (%s)\n",host, cli_errstr(&c_dos));
+       if (!NT_STATUS_IS_OK(cli_session_setup(c_dos, "", "", 0, "", 0,
+                                              workgroup))) {
+               printf("%s rejected the DOS-error initial session setup (%s)\n",host, cli_errstr(c_dos));
                return False;
        }
 
        for (error=(0xc0000000 | 0x1); error < (0xc0000000| 0xFFF); error++) {
-               snprintf(user, sizeof(user), "%X", error);
+               fstr_sprintf(user, "%X", error);
 
-               if (cli_session_setup(&c_nt, user, 
-                                      password, strlen(password),
-                                      password, strlen(password),
-                                     workgroup)) {
+               if (NT_STATUS_IS_OK(cli_session_setup(c_nt, user, 
+                                                     password, strlen(password),
+                                                     password, strlen(password),
+                                                     workgroup))) {
                        printf("/** Session setup succeeded.  This shouldn't happen...*/\n");
                }
                
-               flgs2 = SVAL(c_nt.inbuf,smb_flg2);
+               flgs2 = SVAL(c_nt->inbuf,smb_flg2);
                
                /* Case #1: 32-bit NT errors */
                if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
-                       nt_status = NT_STATUS(IVAL(c_nt.inbuf,smb_rcls));
+                       nt_status = NT_STATUS(IVAL(c_nt->inbuf,smb_rcls));
                } else {
                        printf("/** Dos error on NT connection! (%s) */\n", 
-                              cli_errstr(&c_nt));
+                              cli_errstr(c_nt));
                        nt_status = NT_STATUS(0xc0000000);
                }
 
-               if (cli_session_setup(&c_dos, user, 
-                                      password, strlen(password),
-                                      password, strlen(password),
-                                      workgroup)) {
+               if (NT_STATUS_IS_OK(cli_session_setup(c_dos, user, 
+                                                     password, strlen(password),
+                                                     password, strlen(password),
+                                                     workgroup))) {
                        printf("/** Session setup succeeded.  This shouldn't happen...*/\n");
                }
-               flgs2 = SVAL(c_dos.inbuf,smb_flg2), errnum;
+               flgs2 = SVAL(c_dos->inbuf,smb_flg2), errnum;
                
                /* Case #1: 32-bit NT errors */
                if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
                        printf("/** NT error on DOS connection! (%s) */\n", 
-                              cli_errstr(&c_nt));
+                              cli_errstr(c_nt));
                        errnum = errclass = 0;
                } else {
-                       cli_dos_error(&c_dos, &errclass, &errnum);
+                       cli_dos_error(c_dos, &errclass, &errnum);
                }
 
                if (NT_STATUS_V(nt_status) != error) { 
@@ -4417,6 +4781,101 @@ static BOOL run_error_map_extract(int dummy) {
        return True;
 }
 
+static BOOL run_local_substitute(int dummy)
+{
+       TALLOC_CTX *mem_ctx;
+       int diff = 0;
+
+       if ((mem_ctx = talloc_init("run_local_subst")) == NULL) {
+               printf("talloc_init failed\n");
+               return False;
+       }
+
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%U", "bla", "", -1, -1),
+                      "bla");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%u%U", "bla", "", -1, -1),
+                      "blabla");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%g", "", "", -1, -1),
+                      "NO_GROUP");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%G", "", "", -1, -1),
+                      "NO_GROUP");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%g", "", "", -1, 0),
+                      gidtoname(0));
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%G", "", "", -1, 0),
+                      gidtoname(0));
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%D%u", "u", "dom", -1, 0),
+                      "domu");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%i %I", "", "", -1, -1),
+                      "0.0.0.0 0.0.0.0");
+
+       /* Different captialization rules in sub_basic... */
+
+       diff |= strcmp(talloc_sub_basic(mem_ctx, "BLA", "dom", "%U%D"),
+                      "blaDOM");
+
+       TALLOC_FREE(mem_ctx);
+       return (diff == 0);
+}
+
+static BOOL run_local_gencache(int dummy)
+{
+       char *val;
+       time_t tm;
+
+       if (!gencache_init()) {
+               d_printf("%s: gencache_init() failed\n", __location__);
+               return False;
+       }
+
+       if (!gencache_set("foo", "bar", time(NULL) + 1000)) {
+               d_printf("%s: gencache_set() failed\n", __location__);
+               return False;
+       }
+
+       if (!gencache_get("foo", &val, &tm)) {
+               d_printf("%s: gencache_get() failed\n", __location__);
+               return False;
+       }
+
+       if (strcmp(val, "bar") != 0) {
+               d_printf("%s: gencache_get() returned %s, expected %s\n",
+                        __location__, val, "bar");
+               SAFE_FREE(val);
+               return False;
+       }
+
+       SAFE_FREE(val);
+
+       if (!gencache_del("foo")) {
+               d_printf("%s: gencache_del() failed\n", __location__);
+               return False;
+       }
+       if (gencache_del("foo")) {
+               d_printf("%s: second gencache_del() succeeded\n",
+                        __location__);
+               return False;
+       }
+                       
+       if (gencache_get("foo", &val, &tm)) {
+               d_printf("%s: gencache_get() on deleted entry "
+                        "succeeded\n", __location__);
+               return False;
+       }
+
+       if (!gencache_shutdown()) {
+               d_printf("%s: gencache_shutdown() failed\n", __location__);
+               return False;
+       }
+
+       if (gencache_shutdown()) {
+               d_printf("%s: second gencache_shutdown() succeeded\n",
+                        __location__);
+               return False;
+       }
+
+       return True;
+}
+
 static double create_procs(BOOL (*fn)(int), BOOL *result)
 {
        int i, status;
@@ -4455,17 +4914,17 @@ static double create_procs(BOOL (*fn)(int), BOOL *result)
                        slprintf(myname,sizeof(myname),"CLIENT%d", i);
 
                        while (1) {
-                               if (torture_open_connection(&current_cli)) break;
+                               if (torture_open_connection(&current_cli, i)) break;
                                if (tries-- == 0) {
                                        printf("pid %d failed to start\n", (int)getpid());
                                        _exit(1);
                                }
-                               msleep(10);     
+                               smb_msleep(10); 
                        }
 
                        child_status[i] = getpid();
 
-                       while (child_status[i] && end_timer() < 5) msleep(2);
+                       while (child_status[i] && end_timer() < 5) smb_msleep(2);
 
                        child_status_out[i] = fn(i);
                        _exit(0);
@@ -4478,7 +4937,7 @@ static double create_procs(BOOL (*fn)(int), BOOL *result)
                        if (child_status[i]) synccount++;
                }
                if (synccount == nprocs) break;
-               msleep(10);
+               smb_msleep(10);
        } while (end_timer() < 30);
 
        if (synccount != nprocs) {
@@ -4566,6 +5025,9 @@ static struct {
        {"IOCTL",  torture_ioctl_test, 0},
        {"CHKPATH",  torture_chkpath_test, 0},
        {"FDSESS", run_fdsesstest, 0},
+       { "EATEST", run_eatest, 0},
+       { "LOCAL-SUBSTITUTE", run_local_substitute, 0},
+       { "LOCAL-GENCACHE", run_local_gencache, 0},
        {NULL, NULL, 0}};
 
 
@@ -4577,19 +5039,22 @@ static BOOL run_test(const char *name)
 {
        BOOL ret = True;
        BOOL result = True;
+       BOOL found = False;
        int i;
        double t;
        if (strequal(name,"ALL")) {
                for (i=0;torture_ops[i].name;i++) {
                        run_test(torture_ops[i].name);
                }
+               found = True;
        }
        
        for (i=0;torture_ops[i].name;i++) {
-               snprintf(randomfname, sizeof(randomfname), "\\XX%x", 
+               fstr_sprintf(randomfname, "\\XX%x", 
                         (unsigned)random());
 
                if (strequal(name, torture_ops[i].name)) {
+                       found = True;
                        printf("Running %s\n", name);
                        if (torture_ops[i].flags & FLAG_MULTIPROC) {
                                t = create_procs(torture_ops[i].fn, &result);
@@ -4609,6 +5074,12 @@ static BOOL run_test(const char *name)
                        printf("%s took %g secs\n\n", name, t);
                }
        }
+
+       if (!found) {
+               printf("Did not find a test named %s\n", name);
+               ret = False;
+       }
+
        return ret;
 }
 
@@ -4617,6 +5088,9 @@ static void usage(void)
 {
        int i;
 
+       printf("WARNING samba4 test suite is much more complete nowadays.\n");
+       printf("Please use samba4 torture.\n\n");
+
        printf("Usage: smbtorture //server/share <options> TEST1 TEST2 ...\n");
 
        printf("\t-d debuglevel\n");
@@ -4633,6 +5107,7 @@ static void usage(void)
        printf("\t-A showall\n");
        printf("\t-p port\n");
        printf("\t-s seed\n");
+       printf("\t-b unclist_filename   specify multiple shares for multiple connections\n");
        printf("\n\n");
 
        printf("tests are:");
@@ -4655,8 +5130,6 @@ static void usage(void)
        char *p;
        int gotuser = 0;
        int gotpass = 0;
-       extern char *optarg;
-       extern int optind;
        BOOL correct = True;
 
        dbf = x_stdout;
@@ -4665,7 +5138,9 @@ static void usage(void)
        setbuffer(stdout, NULL, 0);
 #endif
 
-       lp_load(dyn_CONFIGFILE,True,False,False);
+       load_case_tables();
+
+       lp_load(dyn_CONFIGFILE,True,False,False,True);
        load_interfaces();
 
        if (argc < 2) {
@@ -4701,7 +5176,7 @@ static void usage(void)
 
        fstrcpy(workgroup, lp_workgroup());
 
-       while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:m:Ld:Ac:ks:")) != EOF) {
+       while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:m:Ld:Ac:ks:b:")) != EOF) {
                switch (opt) {
                case 'p':
                        port_to_use = atoi(optarg);
@@ -4757,6 +5232,10 @@ static void usage(void)
                                gotpass = 1;
                        }
                        break;
+               case 'b':
+                       fstrcpy(multishare_conn_fname, optarg);
+                       use_multishare_conn = True;
+                       break;
                default:
                        printf("Unknown option %c (%d)\n", (char)opt, opt);
                        usage();
@@ -4776,10 +5255,10 @@ static void usage(void)
        printf("host=%s share=%s user=%s myname=%s\n", 
               host, share, username, myname);
 
-       if (argc == 1) {
+       if (argc == optind) {
                correct = run_test("ALL");
        } else {
-               for (i=1;i<argc;i++) {
+               for (i=optind;i<argc;i++) {
                        if (!run_test(argv[i])) {
                                correct = False;
                        }