YIPEE!!!!!
authorAndrew Tridgell <tridge@samba.org>
Sun, 30 Apr 2000 04:45:16 +0000 (04:45 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sun, 30 Apr 2000 04:45:16 +0000 (04:45 +0000)
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 cc9e007cdfdd300189f89e2a55e4234e47fa842d)

source3/Makefile.in
source3/include/client.h
source3/lib/ms_fnmatch.c [new file with mode: 0644]
source3/lib/util.c
source3/libsmb/clilist.c
source3/utils/masktest.c

index 018927b7936fdd2495fdcf77a2d060e9f8015168..1d551b5443982127f1ff1a397d9d207cfa88d98f 100644 (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 \
index 2a780ece26ac1dc9393f879ce357c7088fccd48e..406f2e972c924afdbe32606b33e777c12b9a4979 100644 (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
diff --git a/source3/lib/ms_fnmatch.c b/source3/lib/ms_fnmatch.c
new file mode 100644 (file)
index 0000000..d9475cb
--- /dev/null
@@ -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
index 981dd51f9daf2a3e62c1a7bd6a463172a06688d0..7d9f6a5a50fa33b26be47ff3350194d38af3f528 100644 (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;
index 4cb477961bf07271767f9f09a122a7dc008e38b6..f2e42be5234c8bda7b3e9456330a75f0bb941f5a 100644 (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);
index f7b6ad1b1b808419f8e2caa1149ae24aa10c2c78..d1a8ddce4b1240f46f7edd9cb60942488b2fa2ab 100644 (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);