Get medieval on our ass about SMB1 file descriptors being 16 bits, not an int.
[bbaumbach/samba-autobuild/.git] / source3 / torture / mangle_test.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester - mangling test
4    Copyright (C) Andrew Tridgell 2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22 extern int torture_numops;
23
24 static TDB_CONTEXT *tdb;
25
26 #define NAME_LENGTH 20
27
28 static unsigned total, collisions, failures;
29
30 static bool test_one(struct cli_state *cli, const char *name)
31 {
32         uint16_t fnum;
33         fstring shortname;
34         fstring name2;
35         NTSTATUS status;
36         TDB_DATA data;
37
38         total++;
39
40         if (!NT_STATUS_IS_OK(cli_open(cli, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, &fnum))) {
41                 printf("open of %s failed (%s)\n", name, cli_errstr(cli));
42                 return False;
43         }
44
45         if (!cli_close(cli, fnum)) {
46                 printf("close of %s failed (%s)\n", name, cli_errstr(cli));
47                 return False;
48         }
49
50         /* get the short name */
51         status = cli_qpathinfo_alt_name(cli, name, shortname);
52         if (!NT_STATUS_IS_OK(status)) {
53                 printf("query altname of %s failed (%s)\n", name, cli_errstr(cli));
54                 return False;
55         }
56
57         fstr_sprintf(name2, "\\mangle_test\\%s", shortname);
58         if (!NT_STATUS_IS_OK(cli_unlink(cli, name2, aSYSTEM | aHIDDEN))) {
59                 printf("unlink of %s  (%s) failed (%s)\n", 
60                        name2, name, cli_errstr(cli));
61                 return False;
62         }
63
64         /* recreate by short name */
65         if (!NT_STATUS_IS_OK(cli_open(cli, name2, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, &fnum))) {
66                 printf("open2 of %s failed (%s)\n", name2, cli_errstr(cli));
67                 return False;
68         }
69         if (!cli_close(cli, fnum)) {
70                 printf("close of %s failed (%s)\n", name, cli_errstr(cli));
71                 return False;
72         }
73
74         /* and unlink by long name */
75         if (!NT_STATUS_IS_OK(cli_unlink(cli, name, aSYSTEM | aHIDDEN))) {
76                 printf("unlink2 of %s  (%s) failed (%s)\n", 
77                        name, name2, cli_errstr(cli));
78                 failures++;
79                 cli_unlink(cli, name2, aSYSTEM | aHIDDEN);
80                 return True;
81         }
82
83         /* see if the short name is already in the tdb */
84         data = tdb_fetch_bystring(tdb, shortname);
85         if (data.dptr) {
86                 /* maybe its a duplicate long name? */
87                 if (!strequal(name, (const char *)data.dptr)) {
88                         /* we have a collision */
89                         collisions++;
90                         printf("Collision between %s and %s   ->  %s "
91                                 " (coll/tot: %u/%u)\n", 
92                                 name, data.dptr, shortname, collisions, total);
93                 }
94                 free(data.dptr);
95         } else {
96                 TDB_DATA namedata;
97                 /* store it for later */
98                 namedata.dptr = CONST_DISCARD(uint8 *, name);
99                 namedata.dsize = strlen(name)+1;
100                 tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
101         }
102
103         return True;
104 }
105
106
107 static void gen_name(char *name)
108 {
109         const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~... ";
110         unsigned max_idx = strlen(chars);
111         unsigned len;
112         int i;
113         char *p;
114
115         fstrcpy(name, "\\mangle_test\\");
116         p = name + strlen(name);
117
118         len = 1 + random() % NAME_LENGTH;
119         
120         for (i=0;i<len;i++) {
121                 p[i] = chars[random() % max_idx];
122         }
123
124         p[i] = 0;
125
126         if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
127                 p[0] = '_';
128         }
129
130         /* have a high probability of a common lead char */
131         if (random() % 2 == 0) {
132                 p[0] = 'A';
133         }
134
135         /* and a medium probability of a common lead string */
136         if (random() % 10 == 0) {
137                 if (strlen(p) <= 5) {
138                         fstrcpy(p, "ABCDE");
139                 } else {
140                         /* try not to kill off the null termination */
141                         memcpy(p, "ABCDE", 5);
142                 }
143         }
144
145         /* and a high probability of a good extension length */
146         if (random() % 2 == 0) {
147                 char *s = strrchr(p, '.');
148                 if (s) {
149                         s[4] = 0;
150                 }
151         }
152
153         /* ..... and a 100% proability of a file not ending in "." */
154         if (p[strlen(p)-1] == '.')
155                 p[strlen(p)-1] = '_';
156 }
157
158
159 bool torture_mangle(int dummy)
160 {
161         static struct cli_state *cli;
162         int i;
163         bool ret = True;
164
165         printf("starting mangle test\n");
166
167         if (!torture_open_connection(&cli, 0)) {
168                 return False;
169         }
170
171         /* we will use an internal tdb to store the names we have used */
172         tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
173         if (!tdb) {
174                 printf("ERROR: Failed to open tdb\n");
175                 return False;
176         }
177
178         cli_unlink(cli, "\\mangle_test\\*", aSYSTEM | aHIDDEN);
179         cli_rmdir(cli, "\\mangle_test");
180
181         if (!NT_STATUS_IS_OK(cli_mkdir(cli, "\\mangle_test"))) {
182                 printf("ERROR: Failed to make directory\n");
183                 return False;
184         }
185
186         for (i=0;i<torture_numops;i++) {
187                 fstring name;
188                 ZERO_STRUCT(name);
189
190                 gen_name(name);
191                 
192                 if (!test_one(cli, name)) {
193                         ret = False;
194                         break;
195                 }
196                 if (total && total % 100 == 0) {
197                         printf("collisions %u/%u  - %.2f%%   (%u failures)\r",
198                                collisions, total, (100.0*collisions) / total, failures);
199                 }
200         }
201
202         cli_unlink(cli, "\\mangle_test\\*", aSYSTEM | aHIDDEN);
203         if (!NT_STATUS_IS_OK(cli_rmdir(cli, "\\mangle_test"))) {
204                 printf("ERROR: Failed to remove directory\n");
205                 return False;
206         }
207
208         printf("\nTotal collisions %u/%u  - %.2f%%   (%u failures)\n",
209                collisions, total, (100.0*collisions) / total, failures);
210
211         torture_close_connection(cli);
212
213         printf("mangle test finished\n");
214         return (ret && (failures == 0));
215 }