- added a mangling test suite that measures the collision rate on
authorAndrew Tridgell <tridge@samba.org>
Fri, 12 Apr 2002 03:26:19 +0000 (03:26 +0000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 12 Apr 2002 03:26:19 +0000 (03:26 +0000)
randomised filenames

- fixed several mangling bugs that the test suite pointed out

source/Makefile.in
source/smbd/mangle_hash2.c
source/torture/mangle_test.c [new file with mode: 0644]
source/torture/torture.c

index 54e3238fba2639ecf4bc845387ac010314c48788..476997512fa4671f63a36b195fec2beb9838127c 100644 (file)
@@ -364,7 +364,7 @@ NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(UBIQX_OBJ) \
                 $(LIBSMB_OBJ) $(LIB_OBJ)
 
 SMBTORTURE_OBJ = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
-               torture/denytest.o \
+               torture/denytest.o torture/mangle_test.o \
        $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
 
 MASKTEST_OBJ = torture/masktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
index 96ca7360b89d0d0dbd93934e6603aab896ef6f58..959a93e07b19f5fb3f89b54b072377a531d3cfb0 100644 (file)
@@ -344,6 +344,7 @@ static BOOL check_cache(char *name)
 
        /* we found it - construct the full name */
        strncpy(extension, name+9, 3);
+       extension[3] = 0;
 
        if (extension[0]) {
                M_DEBUG(0,("check_cache: %s -> %s.%s\n", name, prefix, extension));
@@ -435,6 +436,19 @@ static BOOL name_map(char *name, BOOL need83, BOOL cache83)
        /* find the '.' if any */
        dot_p = strrchr(name, '.');
 
+       if (dot_p) {
+               /* if the extension contains any illegal characters or
+                  is too long or zero length then we treat it as part
+                  of the prefix */
+               for (i=0; i<4 && dot_p[i+1]; i++) {
+                       if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) {
+                               dot_p = NULL;
+                               break;
+                       }
+               }
+               if (i == 0 || i == 4) dot_p = NULL;
+       }
+
        /* the leading character in the mangled name is taken from
           the first character of the name, if it is ascii 
           otherwise '_' is used
diff --git a/source/torture/mangle_test.c b/source/torture/mangle_test.c
new file mode 100644 (file)
index 0000000..9024925
--- /dev/null
@@ -0,0 +1,162 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB torture tester - mangling test
+   Copyright (C) Andrew Tridgell 2002
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdb;
+
+#define NAME_LENGTH 30
+
+static unsigned total, collisions;
+
+static BOOL test_one(struct cli_state *cli, const char *name)
+{
+       int fnum;
+       fstring shortname;
+       fstring name2;
+       NTSTATUS status;
+       TDB_DATA data;
+
+       total++;
+
+       fnum = cli_open(cli, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+       if (fnum == -1) {
+               printf("open of %s failed (%s)\n", name, cli_errstr(cli));
+               return False;
+       }
+
+       if (!cli_close(cli, fnum)) {
+               printf("close of %s failed (%s)\n", name, cli_errstr(cli));
+               return False;
+       }
+
+       /* get the short name */
+       status = cli_qpathinfo_alt_name(cli, name, shortname);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("query altname of %s failed (%s)\n", name, cli_errstr(cli));
+               return False;
+       }
+
+       snprintf(name2, sizeof(name2), "\\mangle_test\\%s", shortname);
+       if (!cli_unlink(cli, name2)) {
+               printf("unlink of %s  (%s) failed (%s)\n", 
+                      name2, name, cli_errstr(cli));
+               return False;
+       }
+
+       /* see if the short name is already in the tdb */
+       data = tdb_fetch_by_string(tdb, shortname);
+       if (data.dptr) {
+               /* maybe its a duplicate long name? */
+               if (strcasecmp(name, data.dptr) != 0) {
+                       /* we have a collision */
+                       collisions++;
+                       printf("Collision between %s and %s   ->  %s\n", 
+                              name, data.dptr, shortname);
+               }
+               free(data.dptr);
+       } else {
+               /* store it for later */
+               tdb_store_by_string(tdb, shortname, name, strlen(name)+1);
+       }
+
+       return True;
+}
+
+
+static void gen_name(char *name)
+{
+       const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~";
+       unsigned max_idx = strlen(chars);
+       unsigned len;
+       int i;
+       char *p;
+
+       fstrcpy(name, "\\mangle_test\\");
+       p = name + strlen(name);
+
+       len = 1 + random() % NAME_LENGTH;
+       
+       for (i=0;i<len;i++) {
+               p[i] = chars[random() % max_idx];
+       }
+
+       p[i] = 0;
+
+       if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
+               p[0] = '_';
+       }
+}
+
+
+BOOL torture_mangle(int dummy)
+{
+       extern int torture_numops;
+       static struct cli_state cli;
+       int i;
+
+       printf("starting mangle test\n");
+
+       if (!torture_open_connection(&cli)) {
+               return False;
+       }
+
+       /* we will use an internal tdb to store the names we have used */
+       tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
+       if (!tdb) {
+               printf("ERROR: Failed to open tdb\n");
+               return False;
+       }
+
+       cli_unlink(&cli, "\\mangle_test\\*");
+       cli_rmdir(&cli, "\\mangle_test");
+
+       if (!cli_mkdir(&cli, "\\mangle_test")) {
+               printf("ERROR: Failed to make directory\n");
+               return False;
+       }
+
+       for (i=0;i<torture_numops;i++) {
+               fstring name;
+
+               gen_name(name);
+
+               if (!test_one(&cli, name)) {
+                       break;
+               }
+               if (total && total % 100 == 0) {
+                       printf("collisions %u/%u  - %.2f%%\r",
+                              collisions, total, (100.0*collisions) / total);
+               }
+       }
+
+       if (!cli_rmdir(&cli, "\\mangle_test")) {
+               printf("ERROR: Failed to remove directory\n");
+               return False;
+       }
+
+       printf("\nTotal collisions %u/%u  - %.2f%%\n",
+              collisions, total, (100.0*collisions) / total);
+
+       torture_close_connection(&cli);
+
+       printf("mangle test finished\n");
+       return True;
+}
index 29eeb802ffe2d37855567794c9d37d17233b7d13..23624d07333a51aa78f8c9f234fde13b882e1110 100644 (file)
@@ -25,7 +25,8 @@
 static fstring host, workgroup, share, password, username, myname;
 static int max_protocol = PROTOCOL_NT1;
 static char *sockops="TCP_NODELAY";
-static int nprocs=1, numops=100;
+static int nprocs=1;
+int torture_numops=100;
 static int procnum; /* records process count number when forking */
 static struct cli_state current_cli;
 static fstring randomfname;
@@ -239,7 +240,7 @@ static BOOL rw_torture(struct cli_state *c)
        }
 
 
-       for (i=0;i<numops;i++) {
+       for (i=0;i<torture_numops;i++) {
                unsigned n = (unsigned)sys_random()%10;
                if (i % 10 == 0) {
                        printf("%d\r", i); fflush(stdout);
@@ -456,7 +457,7 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
                return False;
        }
 
-       for (i=0;i<numops;i++)
+       for (i=0;i<torture_numops;i++)
        {
                size_t buf_size = ((unsigned)sys_random()%(sizeof(buf)-1))+ 1;
                if (i % 10 == 0) {
@@ -1112,7 +1113,7 @@ static BOOL run_locktest3(int dummy)
        uint32 offset;
        BOOL correct = True;
 
-#define NEXT_OFFSET offset += (~(uint32)0) / numops
+#define NEXT_OFFSET offset += (~(uint32)0) / torture_numops
 
        if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
                return False;
@@ -1135,7 +1136,7 @@ static BOOL run_locktest3(int dummy)
                return False;
        }
 
-       for (offset=i=0;i<numops;i++) {
+       for (offset=i=0;i<torture_numops;i++) {
                NEXT_OFFSET;
                if (!cli_lock(&cli1, fnum1, offset-1, 1, 0, WRITE_LOCK)) {
                        printf("lock1 %d failed (%s)\n", 
@@ -1152,7 +1153,7 @@ static BOOL run_locktest3(int dummy)
                }
        }
 
-       for (offset=i=0;i<numops;i++) {
+       for (offset=i=0;i<torture_numops;i++) {
                NEXT_OFFSET;
 
                if (cli_lock(&cli1, fnum1, offset-2, 1, 0, WRITE_LOCK)) {
@@ -1176,7 +1177,7 @@ static BOOL run_locktest3(int dummy)
                }
        }
 
-       for (offset=i=0;i<numops;i++) {
+       for (offset=i=0;i<torture_numops;i++) {
                NEXT_OFFSET;
 
                if (!cli_unlock(&cli1, fnum1, offset-1, 1)) {
@@ -3419,7 +3420,7 @@ static BOOL run_dirtest(int dummy)
        cli_sockopt(&cli, sockops);
 
        srandom(0);
-       for (i=0;i<numops;i++) {
+       for (i=0;i<torture_numops;i++) {
                fstring fname;
                slprintf(fname, sizeof(fname), "\\%x", (int)random());
                fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE);
@@ -3439,7 +3440,7 @@ static BOOL run_dirtest(int dummy)
        printf("dirtest core %g seconds\n", end_timer() - t1);
 
        srandom(0);
-       for (i=0;i<numops;i++) {
+       for (i=0;i<torture_numops;i++) {
                fstring fname;
                slprintf(fname, sizeof(fname), "\\%x", (int)random());
                cli_unlink(&cli, fname);
@@ -3693,6 +3694,7 @@ static struct {
        {"RENAME", run_rename, 0},
        {"DELETE", run_deletetest, 0},
        {"PROPERTIES", run_properties, 0},
+       {"MANGLE", torture_mangle, 0},
        {"W2K", run_w2ktest, 0},
        {"TRANS2SCAN", torture_trans2_scan, 0},
        {"NTTRANSSCAN", torture_nttrans_scan, 0},
@@ -3764,6 +3766,7 @@ static void usage(void)
        printf("\t-L use oplocks\n");
        printf("\t-c CLIENT.TXT   specify client load file for NBENCH\n");
        printf("\t-A showall\n");
+       printf("\t-s seed\n");
        printf("\n\n");
 
        printf("tests are:");
@@ -3834,8 +3837,11 @@ static void usage(void)
 
        fstrcpy(workgroup, lp_workgroup());
 
-       while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:Ld:Ac:k")) != EOF) {
+       while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:Ld:Ac:ks:")) != EOF) {
                switch (opt) {
+               case 's':
+                       srandom(atoi(optarg));
+                       break;
                case 'W':
                        fstrcpy(workgroup,optarg);
                        break;
@@ -3846,7 +3852,7 @@ static void usage(void)
                        nprocs = atoi(optarg);
                        break;
                case 'o':
-                       numops = atoi(optarg);
+                       torture_numops = atoi(optarg);
                        break;
                case 'd':
                        DEBUGLEVEL = atoi(optarg);