libsmb: Fix a typo
[samba.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 #include "system/filesys.h"
22 #include "torture/proto.h"
23 #include "libsmb/libsmb.h"
24 #include "libsmb/clirap.h"
25 #include "util_tdb.h"
26 #include "lib/util/string_wrappers.h"
27
28 extern int torture_numops;
29
30 static TDB_CONTEXT *tdb;
31
32 #define NAME_LENGTH 20
33
34 static unsigned total, collisions, failures;
35
36 static bool test_one(struct cli_state *cli, const char *name)
37 {
38         uint16_t fnum;
39         fstring shortname;
40         fstring name2;
41         NTSTATUS status;
42         TDB_DATA data;
43
44         total++;
45
46         status = cli_openx(cli, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, &fnum);
47         if (!NT_STATUS_IS_OK(status)) {
48                 printf("open of %s failed (%s)\n", name, nt_errstr(status));
49                 return False;
50         }
51
52         status = cli_close(cli, fnum);
53         if (!NT_STATUS_IS_OK(status)) {
54                 printf("close of %s failed (%s)\n", name, nt_errstr(status));
55                 return False;
56         }
57
58         /* get the short name */
59         status = cli_qpathinfo_alt_name(cli, name, shortname);
60         if (!NT_STATUS_IS_OK(status)) {
61                 printf("query altname of %s failed (%s)\n", name, nt_errstr(status));
62                 return False;
63         }
64
65         fstr_sprintf(name2, "\\mangle_test\\%s", shortname);
66         status = cli_unlink(cli, name2, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
67         if (!NT_STATUS_IS_OK(status)) {
68                 printf("unlink of %s  (%s) failed (%s)\n", 
69                        name2, name, nt_errstr(status));
70                 return False;
71         }
72
73         /* recreate by short name */
74         status = cli_openx(cli, name2, O_RDWR|O_CREAT|O_EXCL, DENY_NONE, &fnum);
75         if (!NT_STATUS_IS_OK(status)) {
76                 printf("open2 of %s failed (%s)\n", name2, nt_errstr(status));
77                 return False;
78         }
79
80         status = cli_close(cli, fnum);
81         if (!NT_STATUS_IS_OK(status)) {
82                 printf("close of %s failed (%s)\n", name, nt_errstr(status));
83                 return False;
84         }
85
86         /* and unlink by long name */
87         status = cli_unlink(cli, name, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
88         if (!NT_STATUS_IS_OK(status)) {
89                 printf("unlink2 of %s  (%s) failed (%s)\n", 
90                        name, name2, nt_errstr(status));
91                 failures++;
92                 cli_unlink(cli, name2, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
93                 return True;
94         }
95
96         /* see if the short name is already in the tdb */
97         data = tdb_fetch_bystring(tdb, shortname);
98         if (data.dptr) {
99                 /* maybe its a duplicate long name? */
100                 if (!strequal(name, (const char *)data.dptr)) {
101                         /* we have a collision */
102                         collisions++;
103                         printf("Collision between %s and %s   ->  %s "
104                                 " (coll/tot: %u/%u)\n", 
105                                 name, data.dptr, shortname, collisions, total);
106                 }
107                 free(data.dptr);
108         } else {
109                 TDB_DATA namedata;
110                 /* store it for later */
111                 namedata.dptr = discard_const_p(uint8_t, name);
112                 namedata.dsize = strlen(name)+1;
113                 tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
114         }
115
116         return True;
117 }
118
119
120 static void gen_name(char *name)
121 {
122         const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~... ";
123         unsigned max_idx = strlen(chars);
124         unsigned len;
125         int i;
126         char *p;
127
128         fstrcpy(name, "\\mangle_test\\");
129         p = name + strlen(name);
130
131         len = 1 + random() % NAME_LENGTH;
132         
133         for (i=0;i<len;i++) {
134                 p[i] = chars[random() % max_idx];
135         }
136
137         p[i] = 0;
138
139         if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
140                 p[0] = '_';
141         }
142
143         /* have a high probability of a common lead char */
144         if (random() % 2 == 0) {
145                 p[0] = 'A';
146         }
147
148         /* and a medium probability of a common lead string */
149         if (random() % 10 == 0) {
150                 if (strlen(p) <= 5) {
151                         fstrcpy(p, "ABCDE");
152                 } else {
153                         /* try not to kill off the null termination */
154                         memcpy(p, "ABCDE", 5);
155                 }
156         }
157
158         /* and a high probability of a good extension length */
159         if (random() % 2 == 0) {
160                 char *s = strrchr(p, '.');
161                 if (s) {
162                         s[4] = 0;
163                 }
164         }
165
166         /* ..... and a 100% proability of a file not ending in "." */
167         if (p[strlen(p)-1] == '.')
168                 p[strlen(p)-1] = '_';
169 }
170
171
172 bool torture_mangle(int dummy)
173 {
174         static struct cli_state *cli;
175         int i;
176         bool ret = True;
177
178         printf("starting mangle test\n");
179
180         if (!torture_open_connection(&cli, 0)) {
181                 return False;
182         }
183
184         /* we will use an internal tdb to store the names we have used */
185         tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
186         if (!tdb) {
187                 printf("ERROR: Failed to open tdb\n");
188                 return False;
189         }
190
191         cli_unlink(cli, "\\mangle_test\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
192         cli_rmdir(cli, "\\mangle_test");
193
194         if (!NT_STATUS_IS_OK(cli_mkdir(cli, "\\mangle_test"))) {
195                 printf("ERROR: Failed to make directory\n");
196                 return False;
197         }
198
199         for (i=0;i<torture_numops;i++) {
200                 fstring name;
201                 ZERO_STRUCT(name);
202
203                 gen_name(name);
204                 
205                 if (!test_one(cli, name)) {
206                         ret = False;
207                         break;
208                 }
209                 if (total && total % 100 == 0) {
210                         printf("collisions %u/%u  - %.2f%%   (%u failures)\r",
211                                collisions, total, (100.0*collisions) / total, failures);
212                 }
213         }
214
215         cli_unlink(cli, "\\mangle_test\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
216         if (!NT_STATUS_IS_OK(cli_rmdir(cli, "\\mangle_test"))) {
217                 printf("ERROR: Failed to remove directory\n");
218                 return False;
219         }
220
221         printf("\nTotal collisions %u/%u  - %.2f%%   (%u failures)\n",
222                collisions, total, (100.0*collisions) / total, failures);
223
224         torture_close_connection(cli);
225
226         printf("mangle test finished\n");
227         return (ret && (failures == 0));
228 }