r20124: clean up nested extern declaration warnings
[Samba/gebeck_regimport.git] / source3 / torture / masktest.c
blob2ce59c86e65c118335b31321030eee960692f2b4
1 /*
2 Unix SMB/CIFS implementation.
3 mask_match tester
4 Copyright (C) Andrew Tridgell 1999
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.
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.
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.
21 #include "includes.h"
23 static fstring password;
24 static fstring username;
25 static int got_pass;
26 static int max_protocol = PROTOCOL_NT1;
27 static BOOL showall = False;
28 static BOOL old_list = False;
29 static const char *maskchars = "<>\"?*abc.";
30 static const char *filechars = "abcdefghijklm.";
31 static int verbose;
32 static int die_on_error;
33 static int NumLoops = 0;
34 static int ignore_dot_errors = 0;
36 /* a test fn for LANMAN mask support */
37 int ms_fnmatch_lanman_core(const char *pattern, const char *string)
39 const char *p = pattern, *n = string;
40 char c;
42 if (strcmp(p,"?")==0 && strcmp(n,".")==0) goto match;
44 while ((c = *p++)) {
45 switch (c) {
46 case '.':
47 /* if (! *n && ! *p) goto match; */
48 if (*n != '.') goto nomatch;
49 n++;
50 break;
52 case '?':
53 if ((*n == '.' && n[1] != '.') || ! *n) goto next;
54 n++;
55 break;
57 case '>':
58 if (n[0] == '.') {
59 if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
60 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
61 goto nomatch;
63 if (! *n) goto next;
64 n++;
65 break;
67 case '*':
68 if (! *p) goto match;
69 for (; *n; n++) {
70 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
72 break;
74 case '<':
75 for (; *n; n++) {
76 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
77 if (*n == '.' && !strchr_m(n+1,'.')) {
78 n++;
79 break;
82 break;
84 case '"':
85 if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
86 if (*n != '.') goto nomatch;
87 n++;
88 break;
90 default:
91 if (c != *n) goto nomatch;
92 n++;
96 if (! *n) goto match;
98 nomatch:
99 if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
100 return -1;
102 next:
103 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
104 goto nomatch;
106 match:
107 if (verbose) printf("MATCH pattern=[%s] string=[%s]\n", pattern, string);
108 return 0;
111 int ms_fnmatch_lanman(const char *pattern, const char *string)
113 if (!strpbrk(pattern, "?*<>\"")) {
114 if (strcmp(string,"..") == 0)
115 string = ".";
117 return strcmp(pattern, string);
120 if (strcmp(string,"..") == 0 || strcmp(string,".") == 0) {
121 return ms_fnmatch_lanman_core(pattern, "..") &&
122 ms_fnmatch_lanman_core(pattern, ".");
125 return ms_fnmatch_lanman_core(pattern, string);
128 static BOOL reg_match_one(struct cli_state *cli, const char *pattern, const char *file)
130 /* oh what a weird world this is */
131 if (old_list && strcmp(pattern, "*.*") == 0) return True;
133 if (strcmp(pattern,".") == 0) return False;
135 if (max_protocol <= PROTOCOL_LANMAN2) {
136 return ms_fnmatch_lanman(pattern, file)==0;
139 if (strcmp(file,"..") == 0) file = ".";
141 return ms_fnmatch(pattern, file, cli->protocol, False) == 0;
144 static char *reg_test(struct cli_state *cli, char *pattern, char *long_name, char *short_name)
146 static fstring ret;
147 fstrcpy(ret, "---");
149 pattern = 1+strrchr_m(pattern,'\\');
151 if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
152 if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
153 if (reg_match_one(cli, pattern, long_name) ||
154 (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
155 return ret;
159 /*****************************************************
160 return a connection to a server
161 *******************************************************/
162 struct cli_state *connect_one(char *share)
164 struct cli_state *c;
165 struct nmb_name called, calling;
166 char *server_n;
167 char *server;
168 struct in_addr ip;
170 server = share+2;
171 share = strchr_m(server,'\\');
172 if (!share) return NULL;
173 *share = 0;
174 share++;
176 server_n = server;
178 zero_ip(&ip);
180 make_nmb_name(&calling, "masktest", 0x0);
181 make_nmb_name(&called , server, 0x20);
183 again:
184 zero_ip(&ip);
186 /* have to open a new connection */
187 if (!(c=cli_initialise()) || !cli_connect(c, server_n, &ip)) {
188 DEBUG(0,("Connection to %s failed\n", server_n));
189 return NULL;
192 c->protocol = max_protocol;
194 if (!cli_session_request(c, &calling, &called)) {
195 DEBUG(0,("session request to %s failed\n", called.name));
196 cli_shutdown(c);
197 if (strcmp(called.name, "*SMBSERVER")) {
198 make_nmb_name(&called , "*SMBSERVER", 0x20);
199 goto again;
201 return NULL;
204 DEBUG(4,(" session request ok\n"));
206 if (!cli_negprot(c)) {
207 DEBUG(0,("protocol negotiation failed\n"));
208 cli_shutdown(c);
209 return NULL;
212 if (!got_pass) {
213 char *pass = getpass("Password: ");
214 if (pass) {
215 fstrcpy(password, pass);
219 if (!NT_STATUS_IS_OK(cli_session_setup(c, username,
220 password, strlen(password),
221 password, strlen(password),
222 lp_workgroup()))) {
223 DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
224 return NULL;
228 * These next two lines are needed to emulate
229 * old client behaviour for people who have
230 * scripts based on client output.
231 * QUESTION ? Do we want to have a 'client compatibility
232 * mode to turn these on/off ? JRA.
235 if (*c->server_domain || *c->server_os || *c->server_type)
236 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
237 c->server_domain,c->server_os,c->server_type));
239 DEBUG(4,(" session setup ok\n"));
241 if (!cli_send_tconX(c, share, "?????",
242 password, strlen(password)+1)) {
243 DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
244 cli_shutdown(c);
245 return NULL;
248 DEBUG(4,(" tconx ok\n"));
250 return c;
253 static char *resultp;
254 static file_info *f_info;
256 static void listfn(const char *mnt, file_info *f, const char *s, void *state)
258 if (strcmp(f->name,".") == 0) {
259 resultp[0] = '+';
260 } else if (strcmp(f->name,"..") == 0) {
261 resultp[1] = '+';
262 } else {
263 resultp[2] = '+';
265 f_info = f;
268 static void get_real_name(struct cli_state *cli,
269 pstring long_name, fstring short_name)
271 /* nasty hack to force level 260 listings - tridge */
272 cli->capabilities |= CAP_NT_SMBS;
273 if (max_protocol <= PROTOCOL_LANMAN1) {
274 cli_list_new(cli, "\\masktest\\*.*", aHIDDEN | aDIR, listfn, NULL);
275 } else {
276 cli_list_new(cli, "\\masktest\\*", aHIDDEN | aDIR, listfn, NULL);
278 if (f_info) {
279 fstrcpy(short_name, f_info->short_name);
280 strlower_m(short_name);
281 pstrcpy(long_name, f_info->name);
282 strlower_m(long_name);
285 if (*short_name == 0) {
286 fstrcpy(short_name, long_name);
289 #if 0
290 if (!strchr_m(short_name,'.')) {
291 fstrcat(short_name,".");
293 #endif
296 static void testpair(struct cli_state *cli, char *mask, char *file)
298 int fnum;
299 fstring res1;
300 char *res2;
301 static int count;
302 fstring short_name;
303 pstring long_name;
305 count++;
307 fstrcpy(res1, "---");
309 fnum = cli_open(cli, file, O_CREAT|O_TRUNC|O_RDWR, 0);
310 if (fnum == -1) {
311 DEBUG(0,("Can't create %s\n", file));
312 return;
314 cli_close(cli, fnum);
316 resultp = res1;
317 fstrcpy(short_name, "");
318 f_info = NULL;
319 get_real_name(cli, long_name, short_name);
320 f_info = NULL;
321 fstrcpy(res1, "---");
322 cli_list(cli, mask, aHIDDEN | aDIR, listfn, NULL);
324 res2 = reg_test(cli, mask, long_name, short_name);
326 if (showall ||
327 ((strcmp(res1, res2) && !ignore_dot_errors) ||
328 (strcmp(res1+2, res2+2) && ignore_dot_errors))) {
329 DEBUG(0,("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
330 res1, res2, count, mask, file, long_name, short_name));
331 if (die_on_error) exit(1);
334 cli_unlink(cli, file);
336 if (count % 100 == 0) DEBUG(0,("%d\n", count));
339 static void test_mask(int argc, char *argv[],
340 struct cli_state *cli)
342 pstring mask, file;
343 int l1, l2, i, l;
344 int mc_len = strlen(maskchars);
345 int fc_len = strlen(filechars);
347 cli_mkdir(cli, "\\masktest");
349 cli_unlink(cli, "\\masktest\\*");
351 if (argc >= 2) {
352 while (argc >= 2) {
353 pstrcpy(mask,"\\masktest\\");
354 pstrcpy(file,"\\masktest\\");
355 pstrcat(mask, argv[0]);
356 pstrcat(file, argv[1]);
357 testpair(cli, mask, file);
358 argv += 2;
359 argc -= 2;
361 goto finished;
364 while (1) {
365 l1 = 1 + random() % 20;
366 l2 = 1 + random() % 20;
367 pstrcpy(mask,"\\masktest\\");
368 pstrcpy(file,"\\masktest\\");
369 l = strlen(mask);
370 for (i=0;i<l1;i++) {
371 mask[i+l] = maskchars[random() % mc_len];
373 mask[l+l1] = 0;
375 for (i=0;i<l2;i++) {
376 file[i+l] = filechars[random() % fc_len];
378 file[l+l2] = 0;
380 if (strcmp(file+l,".") == 0 ||
381 strcmp(file+l,"..") == 0 ||
382 strcmp(mask+l,"..") == 0) continue;
384 if (strspn(file+l, ".") == strlen(file+l)) continue;
386 testpair(cli, mask, file);
387 if (NumLoops && (--NumLoops == 0))
388 break;
391 finished:
392 cli_rmdir(cli, "\\masktest");
396 static void usage(void)
398 printf(
399 "Usage:\n\
400 masktest //server/share [options..]\n\
401 options:\n\
402 -d debuglevel\n\
403 -n numloops\n\
404 -W workgroup\n\
405 -U user%%pass\n\
406 -s seed\n\
407 -M max protocol\n\
408 -f filechars (default %s)\n\
409 -m maskchars (default %s)\n\
410 -v verbose mode\n\
411 -E die on error\n\
412 -a show all tests\n\
413 -i ignore . and .. errors\n\
415 This program tests wildcard matching between two servers. It generates\n\
416 random pairs of filenames/masks and tests that they match in the same\n\
417 way on the servers and internally\n\
419 filechars, maskchars);
422 /****************************************************************************
423 main program
424 ****************************************************************************/
425 int main(int argc,char *argv[])
427 char *share;
428 struct cli_state *cli;
429 extern char *optarg;
430 extern int optind;
431 extern BOOL AllowDebugChange;
432 int opt;
433 char *p;
434 int seed;
436 setlinebuf(stdout);
438 dbf = x_stderr;
440 DEBUGLEVEL = 0;
441 AllowDebugChange = False;
443 if (argc < 2 || argv[1][0] == '-') {
444 usage();
445 exit(1);
448 share = argv[1];
450 all_string_sub(share,"/","\\",0);
452 setup_logging(argv[0],True);
454 argc -= 1;
455 argv += 1;
457 lp_load(dyn_CONFIGFILE,True,False,False,True);
458 load_interfaces();
460 if (getenv("USER")) {
461 fstrcpy(username,getenv("USER"));
464 seed = time(NULL);
466 while ((opt = getopt(argc, argv, "n:d:U:s:hm:f:aoW:M:vEi")) != EOF) {
467 switch (opt) {
468 case 'n':
469 NumLoops = atoi(optarg);
470 break;
471 case 'd':
472 DEBUGLEVEL = atoi(optarg);
473 break;
474 case 'E':
475 die_on_error = 1;
476 break;
477 case 'i':
478 ignore_dot_errors = 1;
479 break;
480 case 'v':
481 verbose++;
482 break;
483 case 'M':
484 max_protocol = interpret_protocol(optarg, max_protocol);
485 break;
486 case 'U':
487 fstrcpy(username,optarg);
488 p = strchr_m(username,'%');
489 if (p) {
490 *p = 0;
491 fstrcpy(password, p+1);
492 got_pass = 1;
494 break;
495 case 's':
496 seed = atoi(optarg);
497 break;
498 case 'h':
499 usage();
500 exit(1);
501 case 'm':
502 maskchars = optarg;
503 break;
504 case 'f':
505 filechars = optarg;
506 break;
507 case 'a':
508 showall = 1;
509 break;
510 case 'o':
511 old_list = True;
512 break;
513 default:
514 printf("Unknown option %c (%d)\n", (char)opt, opt);
515 exit(1);
519 argc -= optind;
520 argv += optind;
523 cli = connect_one(share);
524 if (!cli) {
525 DEBUG(0,("Failed to connect to %s\n", share));
526 exit(1);
529 /* need to init seed after connect as clientgen uses random numbers */
530 DEBUG(0,("seed=%d\n", seed));
531 srandom(seed);
533 test_mask(argc, argv, cli);
535 return(0);