2 Unix SMB/CIFS implementation.
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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "lib/cmdline/cmdline.h"
22 #include "system/filesys.h"
23 #include "system/dir.h"
24 #include "libcli/libcli.h"
25 #include "system/time.h"
26 #include "auth/credentials/credentials.h"
27 #include "auth/gensec/gensec.h"
28 #include "param/param.h"
29 #include "libcli/resolve/resolve.h"
30 #include "lib/events/events.h"
32 static bool showall
= false;
33 static bool old_list
= false;
34 static const char *maskchars
= "<>\"?*abc.";
35 static const char *filechars
= "abcdefghijklm.";
36 static int die_on_error
;
37 static int NumLoops
= 0;
38 static int max_length
= 20;
39 struct masktest_state
{
43 static bool reg_match_one(struct smbcli_state
*cli
, const char *pattern
, const char *file
)
45 /* oh what a weird world this is */
46 if (old_list
&& strcmp(pattern
, "*.*") == 0) return true;
48 if (ISDOT(pattern
)) return false;
50 if (ISDOTDOT(file
)) file
= ".";
52 return ms_fnmatch_protocol(
53 pattern
, file
, cli
->transport
->negotiate
.protocol
, false)==0;
56 static char *reg_test(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
, const char *pattern
, const char *long_name
, const char *short_name
)
59 ret
= talloc_strdup(mem_ctx
, "---");
61 pattern
= 1+strrchr_m(pattern
,'\\');
63 if (reg_match_one(cli
, pattern
, ".")) ret
[0] = '+';
64 if (reg_match_one(cli
, pattern
, "..")) ret
[1] = '+';
65 if (reg_match_one(cli
, pattern
, long_name
) ||
66 (*short_name
&& reg_match_one(cli
, pattern
, short_name
))) ret
[2] = '+';
71 /*****************************************************
72 return a connection to a server
73 *******************************************************/
74 static struct smbcli_state
*connect_one(struct resolve_context
*resolve_ctx
,
75 struct tevent_context
*ev
,
77 char *share
, const char **ports
,
78 const char *socket_options
,
79 struct smbcli_options
*options
,
80 struct smbcli_session_options
*session_options
,
81 struct gensec_settings
*gensec_settings
)
83 struct smbcli_state
*c
;
86 struct cli_credentials
*creds
= samba_cmdline_get_creds();
88 server
= talloc_strdup(mem_ctx
, share
+2);
89 share
= strchr_m(server
,'\\');
90 if (!share
) return NULL
;
94 cli_credentials_set_workstation(creds
,
95 "masktest", CRED_SPECIFIED
);
97 status
= smbcli_full_connection(NULL
, &c
,
104 options
, session_options
,
107 if (!NT_STATUS_IS_OK(status
)) {
114 static char *resultp
;
119 static bool f_info_hit
;
121 static void listfn(struct clilist_file_info
*f
, const char *s
, void *state
)
123 struct masktest_state
*m
= (struct masktest_state
*)state
;
125 if (ISDOT(f
->name
)) {
127 } else if (ISDOTDOT(f
->name
)) {
133 last_hit
.long_name
= talloc_strdup(m
->mem_ctx
, f
->name
);
134 last_hit
.short_name
= talloc_strdup(m
->mem_ctx
, f
->short_name
);
138 static void get_real_name(TALLOC_CTX
*mem_ctx
, struct smbcli_state
*cli
,
139 char **long_name
, char **short_name
)
142 struct masktest_state state
;
144 if (cli
->transport
->negotiate
.protocol
<= PROTOCOL_LANMAN1
) {
145 mask
= "\\masktest\\*.*";
147 mask
= "\\masktest\\*";
152 state
.mem_ctx
= mem_ctx
;
154 smbcli_list_new(cli
->tree
, mask
,
155 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
,
156 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
,
160 *short_name
= strlower_talloc(mem_ctx
, last_hit
.short_name
);
161 *long_name
= strlower_talloc(mem_ctx
, last_hit
.long_name
);
164 if (*short_name
[0] == '\0') {
165 *short_name
= talloc_strdup(mem_ctx
, *long_name
);
169 static void testpair(TALLOC_CTX
*mem_ctx
, struct smbcli_state
*cli
, char *mask
,
176 char *short_name
= NULL
;
177 char *long_name
= NULL
;
178 struct masktest_state state
;
182 strlcpy(res1
, "---", sizeof(res1
));
184 state
.mem_ctx
= mem_ctx
;
186 fnum
= smbcli_open(cli
->tree
, file
, O_CREAT
|O_TRUNC
|O_RDWR
, 0);
188 DEBUG(0,("Can't create %s\n", file
));
191 smbcli_close(cli
->tree
, fnum
);
194 short_name
= talloc_strdup(mem_ctx
, "");
195 get_real_name(mem_ctx
, cli
, &long_name
, &short_name
);
196 strlcpy(res1
, "---", sizeof(res1
));
197 smbcli_list_new(cli
->tree
, mask
,
198 FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
,
199 RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
,
202 res2
= reg_test(cli
, mem_ctx
, mask
, long_name
, short_name
);
204 if (showall
|| strcmp(res1
, res2
)) {
205 d_printf("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
206 res1
, res2
, count
, mask
, file
, long_name
, short_name
);
207 if (die_on_error
) exit(1);
210 smbcli_unlink(cli
->tree
, file
);
212 if (count
% 100 == 0) DEBUG(0,("%d\n", count
));
217 static void test_mask(int argc
, char *argv
[],
219 struct smbcli_state
*cli
)
223 int mc_len
= strlen(maskchars
);
224 int fc_len
= strlen(filechars
);
226 smbcli_mkdir(cli
->tree
, "\\masktest");
228 smbcli_unlink_wcard(cli
->tree
, "\\masktest\\*");
232 mask
= talloc_strdup(mem_ctx
, "\\masktest\\");
233 file
= talloc_strdup(mem_ctx
, "\\masktest\\");
234 mask
= talloc_strdup_append(mask
, argv
[0]);
235 file
= talloc_strdup_append(file
, argv
[1]);
236 testpair(mem_ctx
, cli
, mask
, file
);
244 l1
= 1 + random() % max_length
;
245 l2
= 1 + random() % max_length
;
246 mask
= talloc_strdup(mem_ctx
, "\\masktest\\");
247 file
= talloc_strdup(mem_ctx
, "\\masktest\\");
248 mask
= talloc_realloc_size(mem_ctx
, mask
, strlen(mask
)+l1
+1);
249 file
= talloc_realloc_size(mem_ctx
, file
, strlen(file
)+l2
+1);
252 mask
[i
+l
] = maskchars
[random() % mc_len
];
257 file
[i
+l
] = filechars
[random() % fc_len
];
261 if (ISDOT(file
+l
) || ISDOTDOT(file
+l
) || ISDOTDOT(mask
+l
)) {
265 if (strspn(file
+l
, ".") == strlen(file
+l
)) continue;
267 testpair(mem_ctx
, cli
, mask
, file
);
268 if (NumLoops
&& (--NumLoops
== 0))
273 smbcli_rmdir(cli
->tree
, "\\masktest");
277 static void usage(poptContext pc
)
281 masktest //server/share [options..]\n\
283 This program tests wildcard matching between two servers. It generates\n\
284 random pairs of filenames/masks and tests that they match in the same\n\
285 way on the servers and internally\n");
286 poptPrintUsage(pc
, stdout
, 0);
289 /****************************************************************************
291 ****************************************************************************/
292 int main(int argc
, const char *argv
[])
295 struct smbcli_state
*cli
;
298 struct tevent_context
*ev
;
299 struct loadparm_context
*lp_ctx
;
300 struct smbcli_options options
;
301 struct smbcli_session_options session_options
;
305 TALLOC_CTX
*mem_ctx
= NULL
;
306 enum {OPT_UNCLIST
=1000};
307 struct poptOption long_options
[] = {
309 {"seed", 0, POPT_ARG_INT
, &seed
, 0, "Seed to use for randomizer", NULL
},
310 {"num-ops", 0, POPT_ARG_INT
, &NumLoops
, 0, "num ops", NULL
},
311 {"maxlength", 0, POPT_ARG_INT
, &max_length
,0, "maximum length", NULL
},
312 {"dieonerror", 0, POPT_ARG_NONE
, &die_on_error
, 0, "die on errors", NULL
},
313 {"showall", 0, POPT_ARG_NONE
, &showall
, 0, "display all operations", NULL
},
314 {"oldlist", 0, POPT_ARG_NONE
, &old_list
, 0, "use old list call", NULL
},
315 {"maskchars", 0, POPT_ARG_STRING
, &maskchars
, 0,"mask characters", NULL
},
316 {"filechars", 0, POPT_ARG_STRING
, &filechars
, 0,"file characters", NULL
},
318 POPT_COMMON_CONNECTION
319 POPT_COMMON_CREDENTIALS
329 mem_ctx
= talloc_named_const(NULL
, 0, "masktest_ctx");
330 if (mem_ctx
== NULL
) {
334 ok
= samba_cmdline_init(mem_ctx
,
335 SAMBA_CMDLINE_CONFIG_CLIENT
,
336 false /* require_smbconf */);
338 DBG_ERR("Failed to init cmdline parser!\n");
342 pc
= samba_popt_get_context(getprogname(),
346 POPT_CONTEXT_KEEP_FIRST
);
348 DBG_ERR("Failed to setup popt context!\n");
352 poptSetOtherOptionHelp(pc
, "<unc>");
354 lp_ctx
= samba_cmdline_get_lp_ctx();
356 while((opt
= poptGetNextOpt(pc
)) != -1) {
359 lpcfg_set_cmdline(lp_ctx
,
363 case POPT_ERROR_BADOPT
:
364 fprintf(stderr
, "\nInvalid option %s: %s\n\n",
365 poptBadOption(pc
, 0), poptStrerror(opt
));
366 poptPrintUsage(pc
, stderr
, 0);
371 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
373 for (i
=0; i
<argc
; i
++) {
374 if (argv_new
[i
] == NULL
) {
380 if (!(argc_new
>= 2)) {
382 talloc_free(mem_ctx
);
386 setup_logging("masktest", DEBUG_STDOUT
);
390 all_string_sub(share
,"/","\\",0);
392 ev
= s4_event_context_init(mem_ctx
);
396 lpcfg_smbcli_options(lp_ctx
, &options
);
397 lpcfg_smbcli_session_options(lp_ctx
, &session_options
);
399 cli
= connect_one(lpcfg_resolve_context(lp_ctx
), ev
, mem_ctx
, share
,
400 lpcfg_smb_ports(lp_ctx
), lpcfg_socket_options(lp_ctx
),
401 &options
, &session_options
,
402 lpcfg_gensec_settings(mem_ctx
, lp_ctx
));
404 DEBUG(0,("Failed to connect to %s\n", share
));
405 talloc_free(mem_ctx
);
409 /* need to init seed after connect as clientgen uses random numbers */
410 DEBUG(0,("seed=%d format --- --- (server, correct)\n", seed
));
413 test_mask(argc_new
-1, argv_new
+1, mem_ctx
, cli
);
416 talloc_free(mem_ctx
);