r2710: continue with the new style of providing a parent context whenever
[gd/samba-autobuild/.git] / source4 / torture / masktest.c
1 /* 
2    Unix SMB/CIFS implementation.
3    mask_match tester
4    Copyright (C) Andrew Tridgell 1999
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 static fstring password;
24 static fstring username;
25 static BOOL showall = False;
26 static BOOL old_list = False;
27 static const char *maskchars = "<>\"?*abc.";
28 static const char *filechars = "abcdefghijklm.";
29 static int verbose;
30 static int die_on_error;
31 static int NumLoops = 0;
32
33 /* a test fn for LANMAN mask support */
34 static int ms_fnmatch_lanman_core(const char *pattern, const char *string)
35 {
36         const char *p = pattern, *n = string;
37         char c;
38
39         if (strcmp(p,"?")==0 && strcmp(n,".")==0) goto match;
40
41         while ((c = *p++)) {
42                 switch (c) {
43                 case '.':
44                         /* if (! *n && ! *p) goto match; */
45                         if (*n != '.') goto nomatch;
46                         n++;
47                         break;
48
49                 case '?':
50                         if ((*n == '.' && n[1] != '.') || ! *n) goto next;
51                         n++;
52                         break;
53
54                 case '>':
55                         if (n[0] == '.') {
56                                 if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
57                                 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
58                                 goto nomatch;
59                         }
60                         if (! *n) goto next;
61                         n++;
62                         break;
63
64                 case '*':
65                         if (! *p) goto match;
66                         for (; *n; n++) {
67                                 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
68                         }
69                         break;
70
71                 case '<':
72                         for (; *n; n++) {
73                                 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
74                                 if (*n == '.' && !strchr_m(n+1,'.')) {
75                                         n++;
76                                         break;
77                                 }
78                         }
79                         break;
80
81                 case '"':
82                         if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
83                         if (*n != '.') goto nomatch;
84                         n++;
85                         break;
86
87                 default:
88                         if (c != *n) goto nomatch;
89                         n++;
90                 }
91         }
92         
93         if (! *n) goto match;
94         
95  nomatch:
96         if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
97         return -1;
98
99 next:
100         if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
101         goto nomatch;
102
103  match:
104         if (verbose) printf("MATCH   pattern=[%s] string=[%s]\n", pattern, string);
105         return 0;
106 }
107
108 static int ms_fnmatch_lanman(const char *pattern, const char *string)
109 {
110         if (!strpbrk(pattern, "?*<>\"")) {
111                 if (strcmp(string,"..") == 0) 
112                         string = ".";
113
114                 return strcmp(pattern, string);
115         }
116
117         if (strcmp(string,"..") == 0 || strcmp(string,".") == 0) {
118                 return ms_fnmatch_lanman_core(pattern, "..") &&
119                         ms_fnmatch_lanman_core(pattern, ".");
120         }
121
122         return ms_fnmatch_lanman_core(pattern, string);
123 }
124
125 static BOOL reg_match_one(struct smbcli_state *cli, const char *pattern, const char *file)
126 {
127         /* oh what a weird world this is */
128         if (old_list && strcmp(pattern, "*.*") == 0) return True;
129
130         if (strcmp(pattern,".") == 0) return False;
131
132         if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1) {
133                 return ms_fnmatch_lanman(pattern, file)==0;
134         }
135
136         if (strcmp(file,"..") == 0) file = ".";
137
138         return ms_fnmatch(pattern, file, cli->transport->negotiate.protocol)==0;
139 }
140
141 static char *reg_test(struct smbcli_state *cli, char *pattern, char *long_name, char *short_name)
142 {
143         static fstring ret;
144         fstrcpy(ret, "---");
145
146         pattern = 1+strrchr_m(pattern,'\\');
147
148         if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
149         if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
150         if (reg_match_one(cli, pattern, long_name) || 
151             (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
152         return ret;
153 }
154
155
156 /***************************************************** 
157 return a connection to a server
158 *******************************************************/
159 static struct smbcli_state *connect_one(char *share)
160 {
161         struct smbcli_state *c;
162         fstring server;
163         uint_t flags = 0;
164         NTSTATUS status;
165
166         fstrcpy(server,share+2);
167         share = strchr_m(server,'\\');
168         if (!share) return NULL;
169         *share = 0;
170         share++;
171
172         status = smbcli_full_connection(NULL, &c, "masktest",
173                                      server, NULL, 
174                                      share, "?????", 
175                                      username, lp_workgroup(), 
176                                      password, flags, NULL);
177
178         if (!NT_STATUS_IS_OK(status)) {
179                 return NULL;
180         }
181
182         return c;
183 }
184
185 static char *resultp;
186 static struct {
187         pstring long_name;
188         pstring short_name;
189 } last_hit;
190 static BOOL f_info_hit;
191
192 static void listfn(file_info *f, const char *s, void *state)
193 {
194         if (strcmp(f->name,".") == 0) {
195                 resultp[0] = '+';
196         } else if (strcmp(f->name,"..") == 0) {
197                 resultp[1] = '+';               
198         } else {
199                 resultp[2] = '+';
200         }
201         pstrcpy(last_hit.long_name, f->name);
202         pstrcpy(last_hit.short_name, f->short_name);
203         f_info_hit = True;
204 }
205
206 static void get_real_name(struct smbcli_state *cli, 
207                           pstring long_name, fstring short_name)
208 {
209         const char *mask;
210         if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1) {
211                 mask = "\\masktest\\*.*";
212         } else {
213                 mask = "\\masktest\\*";
214         }
215
216         f_info_hit = False;
217
218         smbcli_list_new(cli->tree, mask, 
219                      FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY, 
220                      listfn, NULL);
221
222         if (f_info_hit) {
223                 fstrcpy(short_name, last_hit.short_name);
224                 strlower(short_name);
225                 pstrcpy(long_name, last_hit.long_name);
226                 strlower(long_name);
227         }
228
229         if (*short_name == 0) {
230                 fstrcpy(short_name, long_name);
231         }
232 }
233
234 static void testpair(struct smbcli_state *cli, char *mask, char *file)
235 {
236         int fnum;
237         fstring res1;
238         char *res2;
239         static int count;
240         fstring short_name;
241         pstring long_name;
242
243         count++;
244
245         fstrcpy(res1, "---");
246
247         fnum = smbcli_open(cli->tree, file, O_CREAT|O_TRUNC|O_RDWR, 0);
248         if (fnum == -1) {
249                 DEBUG(0,("Can't create %s\n", file));
250                 return;
251         }
252         smbcli_close(cli->tree, fnum);
253
254         resultp = res1;
255         fstrcpy(short_name, "");
256         get_real_name(cli, long_name, short_name);
257         fstrcpy(res1, "---");
258         smbcli_list(cli->tree, mask, 
259                  FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY, 
260                  listfn, NULL);
261
262         res2 = reg_test(cli, mask, long_name, short_name);
263
264         if (showall || strcmp(res1, res2)) {
265                 d_printf("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
266                          res1, res2, count, mask, file, long_name, short_name);
267                 if (die_on_error) exit(1);
268         }
269
270         smbcli_unlink(cli->tree, file);
271
272         if (count % 100 == 0) DEBUG(0,("%d\n", count));
273 }
274
275 static void test_mask(int argc, char *argv[], 
276                       struct smbcli_state *cli)
277 {
278         pstring mask, file;
279         int l1, l2, i, l;
280         int mc_len = strlen(maskchars);
281         int fc_len = strlen(filechars);
282
283         smbcli_mkdir(cli->tree, "\\masktest");
284
285         smbcli_unlink(cli->tree, "\\masktest\\*");
286
287         if (argc >= 2) {
288                 while (argc >= 2) {
289                         pstrcpy(mask,"\\masktest\\");
290                         pstrcpy(file,"\\masktest\\");
291                         pstrcat(mask, argv[0]);
292                         pstrcat(file, argv[1]);
293                         testpair(cli, mask, file);
294                         argv += 2;
295                         argc -= 2;
296                 }
297                 goto finished;
298         }
299
300         while (1) {
301                 l1 = 1 + random() % 20;
302                 l2 = 1 + random() % 20;
303                 pstrcpy(mask,"\\masktest\\");
304                 pstrcpy(file,"\\masktest\\");
305                 l = strlen(mask);
306                 for (i=0;i<l1;i++) {
307                         mask[i+l] = maskchars[random() % mc_len];
308                 }
309                 mask[l+l1] = 0;
310
311                 for (i=0;i<l2;i++) {
312                         file[i+l] = filechars[random() % fc_len];
313                 }
314                 file[l+l2] = 0;
315
316                 if (strcmp(file+l,".") == 0 || 
317                     strcmp(file+l,"..") == 0 ||
318                     strcmp(mask+l,"..") == 0) continue;
319
320                 if (strspn(file+l, ".") == strlen(file+l)) continue;
321
322                 testpair(cli, mask, file);
323                 if (NumLoops && (--NumLoops == 0))
324                         break;
325         }
326
327  finished:
328         smbcli_rmdir(cli->tree, "\\masktest");
329 }
330
331
332 static void usage(void)
333 {
334         printf(
335 "Usage:\n\
336   masktest //server/share [options..]\n\
337   options:\n\
338         -d debuglevel\n\
339         -n numloops\n\
340         -W workgroup\n\
341         -U user%%pass\n\
342         -s seed\n\
343         -M max protocol\n\
344         -f filechars (default %s)\n\
345         -m maskchars (default %s)\n\
346         -v                             verbose mode\n\
347         -E                             die on error\n\
348         -a                             show all tests\n\
349 \n\
350   This program tests wildcard matching between two servers. It generates\n\
351   random pairs of filenames/masks and tests that they match in the same\n\
352   way on the servers and internally\n\
353 ", 
354   filechars, maskchars);
355 }
356
357 /****************************************************************************
358   main program
359 ****************************************************************************/
360  int main(int argc,char *argv[])
361 {
362         char *share;
363         struct smbcli_state *cli;       
364         int opt;
365         char *p;
366         int seed;
367
368         setlinebuf(stdout);
369
370         setup_logging("masktest", DEBUG_STDOUT);
371
372         lp_set_cmdline("log level", "0");
373
374         if (argc < 2 || argv[1][0] == '-') {
375                 usage();
376                 exit(1);
377         }
378
379         share = argv[1];
380
381         all_string_sub(share,"/","\\",0);
382
383         setup_logging(argv[0], DEBUG_STDOUT);
384
385         argc -= 1;
386         argv += 1;
387
388         lp_load(dyn_CONFIGFILE,True,False,False);
389         load_interfaces();
390
391         if (getenv("USER")) {
392                 fstrcpy(username,getenv("USER"));
393         }
394
395         seed = time(NULL);
396
397         while ((opt = getopt(argc, argv, "n:d:U:s:hm:f:aoW:M:vE")) != EOF) {
398                 switch (opt) {
399                 case 'n':
400                         NumLoops = atoi(optarg);
401                         break;
402                 case 'd':
403                         DEBUGLEVEL = atoi(optarg);
404                         break;
405                 case 'E':
406                         die_on_error = 1;
407                         break;
408                 case 'v':
409                         verbose++;
410                         break;
411                 case 'M':
412                         lp_set_cmdline("max protocol", optarg);
413                         break;
414                 case 'U':
415                         fstrcpy(username,optarg);
416                         p = strchr_m(username,'%');
417                         if (p) {
418                                 *p = 0;
419                                 fstrcpy(password, p+1);
420                         }
421                         break;
422                 case 's':
423                         seed = atoi(optarg);
424                         break;
425                 case 'h':
426                         usage();
427                         exit(1);
428                 case 'm':
429                         maskchars = optarg;
430                         break;
431                 case 'f':
432                         filechars = optarg;
433                         break;
434                 case 'a':
435                         showall = 1;
436                         break;
437                 case 'o':
438                         old_list = True;
439                         break;
440                 default:
441                         printf("Unknown option %c (%d)\n", (char)opt, opt);
442                         exit(1);
443                 }
444         }
445
446         argc -= optind;
447         argv += optind;
448
449
450         cli = connect_one(share);
451         if (!cli) {
452                 DEBUG(0,("Failed to connect to %s\n", share));
453                 exit(1);
454         }
455
456         /* need to init seed after connect as clientgen uses random numbers */
457         DEBUG(0,("seed=%d     format --- --- (server, correct)\n", seed));
458         srandom(seed);
459
460         test_mask(argc, argv, cli);
461
462         return(0);
463 }