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:
parent
c0e1c65053
commit
71e7974f3f
@ -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 \
|
||||
|
@ -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
146
source3/lib/ms_fnmatch.c
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user