r5941: Commit this patch much earlier than I would normally prefer, but metze needs...
[bbaumbach/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 #include "system/filesys.h"
23 #include "dynconfig.h"
24 #include "clilist.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "system/time.h"
27
28 static struct cli_credentials *credentials;
29 static BOOL showall = False;
30 static BOOL old_list = False;
31 static const char *maskchars = "<>\"?*abc.";
32 static const char *filechars = "abcdefghijklm.";
33 static int verbose;
34 static int die_on_error;
35 static int NumLoops = 0;
36 static int max_length = 20;
37
38 static BOOL reg_match_one(struct smbcli_state *cli, const char *pattern, const char *file)
39 {
40         /* oh what a weird world this is */
41         if (old_list && strcmp(pattern, "*.*") == 0) return True;
42
43         if (strcmp(pattern,".") == 0) return False;
44
45         if (strcmp(file,"..") == 0) file = ".";
46
47         return ms_fnmatch(pattern, file, cli->transport->negotiate.protocol)==0;
48 }
49
50 static char *reg_test(struct smbcli_state *cli, char *pattern, char *long_name, char *short_name)
51 {
52         static fstring ret;
53         fstrcpy(ret, "---");
54
55         pattern = 1+strrchr_m(pattern,'\\');
56
57         if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
58         if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
59         if (reg_match_one(cli, pattern, long_name) || 
60             (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
61         return ret;
62 }
63
64
65 /***************************************************** 
66 return a connection to a server
67 *******************************************************/
68 static struct smbcli_state *connect_one(char *share)
69 {
70         struct smbcli_state *c;
71         fstring server;
72         NTSTATUS status;
73
74         fstrcpy(server,share+2);
75         share = strchr_m(server,'\\');
76         if (!share) return NULL;
77         *share = 0;
78         share++;
79
80         status = smbcli_full_connection(NULL, &c, "masktest",
81                                         server, 
82                                         share, NULL,
83                                         credentials);
84
85         if (!NT_STATUS_IS_OK(status)) {
86                 return NULL;
87         }
88
89         return c;
90 }
91
92 static char *resultp;
93 static struct {
94         pstring long_name;
95         pstring short_name;
96 } last_hit;
97 static BOOL f_info_hit;
98
99 static void listfn(struct clilist_file_info *f, const char *s, void *state)
100 {
101         if (strcmp(f->name,".") == 0) {
102                 resultp[0] = '+';
103         } else if (strcmp(f->name,"..") == 0) {
104                 resultp[1] = '+';               
105         } else {
106                 resultp[2] = '+';
107         }
108         pstrcpy(last_hit.long_name, f->name);
109         pstrcpy(last_hit.short_name, f->short_name);
110         f_info_hit = True;
111 }
112
113 static void get_real_name(struct smbcli_state *cli, 
114                           pstring long_name, fstring short_name)
115 {
116         const char *mask;
117         if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1) {
118                 mask = "\\masktest\\*.*";
119         } else {
120                 mask = "\\masktest\\*";
121         }
122
123         f_info_hit = False;
124
125         smbcli_list_new(cli->tree, mask, 
126                         FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY, 
127                         RAW_SEARCH_BOTH_DIRECTORY_INFO,
128                         listfn, NULL);
129
130         if (f_info_hit) {
131                 fstrcpy(short_name, last_hit.short_name);
132                 strlower(short_name);
133                 pstrcpy(long_name, last_hit.long_name);
134                 strlower(long_name);
135         }
136
137         if (*short_name == 0) {
138                 fstrcpy(short_name, long_name);
139         }
140 }
141
142 static void testpair(struct smbcli_state *cli, char *mask, char *file)
143 {
144         int fnum;
145         fstring res1;
146         char *res2;
147         static int count;
148         fstring short_name;
149         pstring long_name;
150
151         count++;
152
153         fstrcpy(res1, "---");
154
155         fnum = smbcli_open(cli->tree, file, O_CREAT|O_TRUNC|O_RDWR, 0);
156         if (fnum == -1) {
157                 DEBUG(0,("Can't create %s\n", file));
158                 return;
159         }
160         smbcli_close(cli->tree, fnum);
161
162         resultp = res1;
163         fstrcpy(short_name, "");
164         get_real_name(cli, long_name, short_name);
165         fstrcpy(res1, "---");
166         smbcli_list_new(cli->tree, mask, 
167                         FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY, 
168                         RAW_SEARCH_BOTH_DIRECTORY_INFO,
169                         listfn, NULL);
170
171         res2 = reg_test(cli, mask, long_name, short_name);
172
173         if (showall || strcmp(res1, res2)) {
174                 d_printf("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
175                          res1, res2, count, mask, file, long_name, short_name);
176                 if (die_on_error) exit(1);
177         }
178
179         smbcli_unlink(cli->tree, file);
180
181         if (count % 100 == 0) DEBUG(0,("%d\n", count));
182 }
183
184 static void test_mask(int argc, char *argv[], 
185                       struct smbcli_state *cli)
186 {
187         pstring mask, file;
188         int l1, l2, i, l;
189         int mc_len = strlen(maskchars);
190         int fc_len = strlen(filechars);
191
192         smbcli_mkdir(cli->tree, "\\masktest");
193
194         smbcli_unlink(cli->tree, "\\masktest\\*");
195
196         if (argc >= 2) {
197                 while (argc >= 2) {
198                         pstrcpy(mask,"\\masktest\\");
199                         pstrcpy(file,"\\masktest\\");
200                         pstrcat(mask, argv[0]);
201                         pstrcat(file, argv[1]);
202                         testpair(cli, mask, file);
203                         argv += 2;
204                         argc -= 2;
205                 }
206                 goto finished;
207         }
208
209         while (1) {
210                 l1 = 1 + random() % max_length;
211                 l2 = 1 + random() % max_length;
212                 pstrcpy(mask,"\\masktest\\");
213                 pstrcpy(file,"\\masktest\\");
214                 l = strlen(mask);
215                 for (i=0;i<l1;i++) {
216                         mask[i+l] = maskchars[random() % mc_len];
217                 }
218                 mask[l+l1] = 0;
219
220                 for (i=0;i<l2;i++) {
221                         file[i+l] = filechars[random() % fc_len];
222                 }
223                 file[l+l2] = 0;
224
225                 if (strcmp(file+l,".") == 0 || 
226                     strcmp(file+l,"..") == 0 ||
227                     strcmp(mask+l,"..") == 0) continue;
228
229                 if (strspn(file+l, ".") == strlen(file+l)) continue;
230
231                 testpair(cli, mask, file);
232                 if (NumLoops && (--NumLoops == 0))
233                         break;
234         }
235
236  finished:
237         smbcli_rmdir(cli->tree, "\\masktest");
238 }
239
240
241 static void usage(void)
242 {
243         printf(
244 "Usage:\n\
245   masktest //server/share [options..]\n\
246   options:\n\
247         -d debuglevel\n\
248         -n numloops\n\
249         -W workgroup\n\
250         -U user%%pass\n\
251         -s seed\n\
252         -l max test length\n\
253         -M max protocol\n\
254         -f filechars (default %s)\n\
255         -m maskchars (default %s)\n\
256         -v                             verbose mode\n\
257         -E                             die on error\n\
258         -a                             show all tests\n\
259 \n\
260   This program tests wildcard matching between two servers. It generates\n\
261   random pairs of filenames/masks and tests that they match in the same\n\
262   way on the servers and internally\n\
263 ", 
264   filechars, maskchars);
265 }
266
267 /****************************************************************************
268   main program
269 ****************************************************************************/
270  int main(int argc,char *argv[])
271 {
272         char *share;
273         struct smbcli_state *cli;       
274         int opt;
275         int seed;
276
277         setlinebuf(stdout);
278
279         setup_logging("masktest", DEBUG_STDOUT);
280
281         lp_set_cmdline("log level", "0");
282
283         if (argc < 2 || argv[1][0] == '-') {
284                 usage();
285                 exit(1);
286         }
287
288         share = argv[1];
289
290         all_string_sub(share,"/","\\",0);
291
292         setup_logging(argv[0], DEBUG_STDOUT);
293
294         argc -= 1;
295         argv += 1;
296
297         lp_load(dyn_CONFIGFILE,True,False,False);
298         load_interfaces();
299
300         credentials = cli_credentials_init(talloc_autofree_context());
301         cli_credentials_guess(credentials);
302
303         seed = time(NULL);
304
305         init_iconv();
306
307         while ((opt = getopt(argc, argv, "n:d:U:s:hm:f:aoW:M:vEl:")) != EOF) {
308                 switch (opt) {
309                 case 'n':
310                         NumLoops = atoi(optarg);
311                         break;
312                 case 'd':
313                         DEBUGLEVEL = atoi(optarg);
314                         break;
315                 case 'E':
316                         die_on_error = 1;
317                         break;
318                 case 'v':
319                         verbose++;
320                         break;
321                 case 'M':
322                         lp_set_cmdline("max protocol", optarg);
323                         break;
324                 case 'U':
325                         cli_credentials_parse_string(credentials, optarg, CRED_SPECIFIED);
326                         break;
327                 case 's':
328                         seed = atoi(optarg);
329                         break;
330                 case 'h':
331                         usage();
332                         exit(1);
333                 case 'm':
334                         maskchars = optarg;
335                         break;
336                 case 'l':
337                         max_length = atoi(optarg);
338                         break;
339                 case 'f':
340                         filechars = optarg;
341                         break;
342                 case 'a':
343                         showall = 1;
344                         break;
345                 case 'o':
346                         old_list = True;
347                         break;
348                 default:
349                         printf("Unknown option %c (%d)\n", (char)opt, opt);
350                         exit(1);
351                 }
352         }
353
354         masktest_init_subsystems;
355
356         argc -= optind;
357         argv += optind;
358
359         cli = connect_one(share);
360         if (!cli) {
361                 DEBUG(0,("Failed to connect to %s\n", share));
362                 exit(1);
363         }
364
365         /* need to init seed after connect as clientgen uses random numbers */
366         DEBUG(0,("seed=%d     format --- --- (server, correct)\n", seed));
367         srandom(seed);
368
369         test_mask(argc, argv, cli);
370
371         return(0);
372 }