1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

YIPEE!!!!!

We finally have a perfect emulation of Microsoft wildcard
matching. The routine ms_fnmatch() does wildcard matching with all MS
wildcards (including the unicode wildcards), and masktest against a
NT4 workstation with hundreds of thousands of random exmaples has not
found a single error.

amazingly it is only about 60 lines of code, but it has taken us years
to get it right. I didn't sleep much last night :)
(This used to be commit cc9e007cdf)
This commit is contained in:
Andrew Tridgell 2000-04-30 04:45:16 +00:00
parent c0e1c65053
commit 71e7974f3f
6 changed files with 166 additions and 79 deletions

View File

@ -109,6 +109,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \
lib/util_unistr.o lib/util_file.o \
lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o lib/fnmatch.o \
lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \
lib/ms_fnmatch.o \
$(TDB_OBJ)
UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \

View File

@ -44,6 +44,7 @@ typedef struct file_info
time_t atime;
time_t ctime;
pstring name;
char short_name[13];
} file_info;
struct print_job_info

146
source3/lib/ms_fnmatch.c Normal file
View File

@ -0,0 +1,146 @@
/*
Unix SMB/Netbios implementation.
Version 3.0
Copyright (C) Andrew Tridgell 1992-1998
This module is derived from fnmatch.c copyright by the Free
Software Foundation. It has been extensively modified to implement
the wildcard matcing semantics of Microsoft SMB servers.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* this matches only filenames, with no directory component */
#if FNMATCH_TEST
#include <stdio.h>
#include <stdlib.h>
#else
#include "includes.h"
#endif
/* the following function was derived using the masktest utility -
after years of effort we finally have a perfect MS wildcard
matching routine! */
int ms_fnmatch(char *pattern, char *string)
{
char *p = pattern, *n = string;
char c;
while ((c = *p++)) {
switch (c) {
case '?':
if (! *n) return -1;
n++;
break;
case '>':
if (n[0] == '.') {
if (! n[1] && ms_fnmatch(p, n+1) == 0) return 0;
if (ms_fnmatch(p, n) == 0) return 0;
return -1;
}
if (! *n) return ms_fnmatch(p, n);
n++;
break;
case '*':
for (; *n; n++) {
if (ms_fnmatch(p, n) == 0) return 0;
}
break;
case '<':
for (; *n; n++) {
if (ms_fnmatch(p, n) == 0) return 0;
if (*n == '.' && !strchr(n+1,'.')) {
n++;
break;
}
}
break;
case '"':
if (*n == 0 && ms_fnmatch(p, n) == 0) return 0;
if (*n != '.') return -1;
n++;
break;
default:
if (c != *n) return -1;
n++;
}
}
if (! *n) return 0;
return -1;
}
#if FNMATCH_TEST
static int match_one(char *pattern, char *file)
{
if (strcmp(file,"..") == 0) file = ".";
if (strcmp(pattern,".") == 0) return -1;
return ms_fnmatch(pattern, file);
}
static char *match_test(char *pattern, char *file, char *short_name)
{
static char ret[4];
strncpy(ret, "---", 3);
if (match_one(pattern, ".") == 0) ret[0] = '+';
if (match_one(pattern, "..") == 0) ret[1] = '+';
if (match_one(pattern, file) == 0 ||
(*short_name && match_one(pattern, short_name)==0)) ret[2] = '+';
return ret;
}
int main(int argc, char *argv[])
{
int ret;
char ans[4], mask[100], file[100], mfile[100];
char *ans2;
int n, i=0;
char line[200];
if (argc == 3) {
ret = ms_fnmatch(argv[1], argv[2]);
if (ret == 0)
printf("YES\n");
else printf("NO\n");
return ret;
}
mfile[0] = 0;
while (fgets(line, sizeof(line)-1, stdin)) {
n = sscanf(line, "%3s %s %s %s\n", ans, mask, file, mfile);
if (n < 3) continue;
ans2 = match_test(mask, file, mfile);
if (strcmp(ans2, ans)) {
printf("%s %s %d mask=[%s] file=[%s] mfile=[%s]\n",
ans, ans2, i, mask, file, mfile);
}
i++;
mfile[0] = 0;
}
return 0;
}
#endif

View File

@ -63,7 +63,7 @@ extern int DEBUGLEVEL;
int Protocol = PROTOCOL_COREPLUS;
/* a default finfo structure to ensure all fields are sensible */
file_info def_finfo = {-1,0,0,0,0,0,0,""};
file_info def_finfo = {-1,0,0,0,0,0,0,"",""};
/* this is used by the chaining code */
int chain_size = 0;

View File

@ -123,6 +123,7 @@ static int interpret_long_filename(int level,char *p,file_info *finfo)
namelen = IVAL(p,0); p += 4;
p += 4; /* EA size */
p += 2; /* short name len? */
unistr_to_ascii(finfo->short_name, p, 12);
p += 24; /* short name? */
StrnCpy(finfo->name,p,MIN(sizeof(finfo->name)-1,namelen));
dos_to_unix(finfo->name,True);

View File

@ -43,82 +43,15 @@ char *standard_files[] = {"abc", "abc.", ".abc",
NULL};
#include <regex.h>
static BOOL reg_match_one(char *pattern, char *file)
{
pstring rpattern;
pstring rfile;
pstrcpy(rpattern, pattern);
if (strcmp(file,"..") == 0) file = ".";
if (strcmp(rpattern,".") == 0) return False;
all_string_sub(rpattern,"\"", ".", 0);
all_string_sub(rpattern,"<", "*", 0);
all_string_sub(rpattern,"*>", "*", 0);
all_string_sub(rpattern,">*", "*", 0);
all_string_sub(rpattern,">", "?", 0);
if (is_8_3(file, False)) {
return fnmatch(rpattern, file, 0)==0;
}
pstrcpy(rfile, file);
mangle_name_83(rfile);
strlower(rfile);
return (fnmatch(rpattern, file, 0)==0 ||
fnmatch(rpattern, rfile, 0)==0);
}
static BOOL regex_reg_match_one(char *pattern, char *file)
{
pstring rpattern;
regex_t preg;
BOOL ret = False;
return fnmatch(pattern, file, 0)==0;
if (strcmp(file,"..") == 0) file = ".";
if (strcmp(pattern,".") == 0) return False;
if (strcmp(pattern,"") == 0) {
if (strcmp(file,".") == 0) return False;
return True;
}
pstrcpy(rpattern,"^");
pstrcat(rpattern, pattern);
all_string_sub(rpattern,".", "[.]", 0);
all_string_sub(rpattern,"?", ".{1}", 0);
all_string_sub(rpattern,"*", ".*", 0);
all_string_sub(rpattern+strlen(rpattern)-1,">", "([^.]?|[.]?$)", 0);
all_string_sub(rpattern,">", "[^.]?", 0);
all_string_sub(rpattern,"<[.]", ".*[.]", 0);
all_string_sub(rpattern,"<\"", "(.*[.]|.*$)", 0);
all_string_sub(rpattern,"<", "([^.]*|[^.]*[.]|[.][^.]*|[.].*[.])", 0);
if (strlen(pattern)>1) {
all_string_sub(rpattern+strlen(rpattern)-1,"\"", "[.]?", 0);
}
all_string_sub(rpattern,"\"", "([.]|$)", 0);
pstrcat(rpattern,"$");
/* printf("pattern=[%s] rpattern=[%s]\n", pattern, rpattern); */
regcomp(&preg, rpattern, REG_ICASE|REG_NOSUB|REG_EXTENDED);
ret = (regexec(&preg, file, 0, NULL, 0) == 0);
regfree(&preg);
return ret;
return ms_fnmatch(pattern, file)==0;
}
static char *reg_test(char *pattern, char *file)
static char *reg_test(char *pattern, char *file, char *short_name)
{
static fstring ret;
fstrcpy(ret, "---");
@ -128,7 +61,8 @@ static char *reg_test(char *pattern, char *file)
if (reg_match_one(pattern, ".")) ret[0] = '+';
if (reg_match_one(pattern, "..")) ret[1] = '+';
if (reg_match_one(pattern, file)) ret[2] = '+';
if (reg_match_one(pattern, file) ||
(*short_name && reg_match_one(pattern, short_name))) ret[2] = '+';
return ret;
}
@ -228,6 +162,7 @@ struct cli_state *connect_one(char *share)
}
static char *resultp;
static file_info *finfo;
void listfn(file_info *f, const char *s)
{
@ -238,6 +173,7 @@ void listfn(file_info *f, const char *s)
} else {
resultp[2] = '+';
}
finfo = f;
}
@ -248,12 +184,14 @@ static void testpair(struct cli_state *cli1, struct cli_state *cli2,
fstring res1, res2;
char *res3;
static int count;
fstring short_name;
count++;
fstrcpy(res1, "---");
fstrcpy(res2, "---");
fnum = cli_open(cli1, file, O_CREAT|O_TRUNC|O_RDWR, 0);
if (fnum == -1) {
DEBUG(0,("Can't create %s on cli1\n", file));
@ -269,22 +207,22 @@ static void testpair(struct cli_state *cli1, struct cli_state *cli2,
cli_close(cli2, fnum);
resultp = res1;
fstrcpy(short_name, "");
finfo = NULL;
cli_list(cli1, mask, aHIDDEN | aDIR, listfn);
if (finfo) {
fstrcpy(short_name, finfo->short_name);
strlower(short_name);
}
res3 = reg_test(mask, file);
res3 = reg_test(mask, file, short_name);
resultp = res2;
cli_list(cli2, mask, aHIDDEN | aDIR, listfn);
if (showall || strcmp(res1, res3)) {
char *p;
pstring rfile;
p = strrchr(file,'\\');
pstrcpy(rfile, p+1);
mangle_name_83(rfile);
strlower(rfile);
DEBUG(0,("%s %s %s %d mask=[%s] file=[%s] mfile=[%s]\n",
res1, res2, res3, count, mask, file, rfile));
res1, res2, res3, count, mask, file, short_name));
}
cli_unlink(cli1, file);