lib/util Use lib/util/ms_fnmatch.c in common for gen_fnmatch()
[abartlet/samba.git/.git] / source3 / lib / ms_fnmatch.c
index a0cbfd2ee21cbad8cdcbe119524727484420e93c..272355b7d203d707c2aa943eba6c85480408fb86 100644 (file)
@@ -1,28 +1,27 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    filename matching routine
    Copyright (C) Andrew Tridgell 1992-2004
 
    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
+   the Free Software Foundation; either version 3 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.  
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
    This module was originally based on fnmatch.c copyright by the Free
    Software Foundation. It bears little (if any) resemblence to that
    code now
-*/  
+*/
 
 
 #include "includes.h"
@@ -54,9 +53,9 @@ struct max_n {
   an optimisation only. The ldot pointer is NULL if the string does
   not contain a '.', otherwise it points at the last dot in 'n'.
 */
-static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n, 
+static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n,
                           struct max_n *max_n, const smb_ucs2_t *ldot,
-                          BOOL is_case_sensitive)
+                          bool is_case_sensitive)
 {
        smb_ucs2_t c;
        int i;
@@ -130,7 +129,7 @@ static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n,
                                if (is_case_sensitive) {
                                        return -1;
                                }
-                               if (toupper_w(c) != toupper_w(*n)) {
+                               if (toupper_m(c) != toupper_m(*n)) {
                                        return -1;
                                }
                        }
@@ -138,22 +137,26 @@ static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n,
                        break;
                }
        }
-       
+
        if (! *n) {
                return 0;
        }
-       
+
        return -1;
 }
 
-int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol, 
-              BOOL is_case_sensitive)
+int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern,
+              bool is_case_sensitive)
 {
-       wpstring p, s;
+       smb_ucs2_t *p = NULL;
+       smb_ucs2_t *s = NULL;
        int ret, count, i;
        struct max_n *max_n = NULL;
+       struct max_n *max_n_free = NULL;
+       struct max_n one_max_n;
+       size_t converted_size;
 
-       if (strcmp(string, "..") == 0) {
+       if (ISDOTDOT(string)) {
                string = ".";
        }
 
@@ -167,19 +170,16 @@ int ms_fnmatch(const char *pattern, const char *string, enum protocol_types prot
                }
        }
 
-       if (push_ucs2(NULL, p, pattern, sizeof(p), STR_TERMINATE) == (size_t)-1) {
-               /* Not quite the right answer, but finding the right one
-                 under this failure case is expensive, and it's pretty close */
+       if (!push_ucs2_talloc(talloc_tos(), &p, pattern, &converted_size)) {
                return -1;
        }
 
-       if (push_ucs2(NULL, s, string, sizeof(s), STR_TERMINATE) == (size_t)-1) {
-               /* Not quite the right answer, but finding the right one
-                  under this failure case is expensive, and it's pretty close */
+       if (!push_ucs2_talloc(talloc_tos(), &s, string, &converted_size)) {
+               TALLOC_FREE(p);
                return -1;
        }
 
-       if (protocol <= PROTOCOL_LANMAN2) {
+       if (translate_pattern) {
                /*
                  for older negotiated protocols it is possible to
                  translate the pattern to produce a "new style"
@@ -188,8 +188,8 @@ int ms_fnmatch(const char *pattern, const char *string, enum protocol_types prot
                for (i=0;p[i];i++) {
                        if (p[i] == UCS2_CHAR('?')) {
                                p[i] = UCS2_CHAR('>');
-                       } else if (p[i] == UCS2_CHAR('.') && 
-                                  (p[i+1] == UCS2_CHAR('?') || 
+                       } else if (p[i] == UCS2_CHAR('.') &&
+                                  (p[i+1] == UCS2_CHAR('?') ||
                                    p[i+1] == UCS2_CHAR('*') ||
                                    p[i+1] == 0)) {
                                p[i] = UCS2_CHAR('"');
@@ -204,24 +204,28 @@ int ms_fnmatch(const char *pattern, const char *string, enum protocol_types prot
        }
 
        if (count != 0) {
-               max_n = SMB_CALLOC_ARRAY(struct max_n, count);
-               if (!max_n) {
-                       return -1;
+               if (count == 1) {
+                       /*
+                        * We're doing this a LOT, so save the effort to allocate
+                        */
+                       ZERO_STRUCT(one_max_n);
+                       max_n = &one_max_n;
+               }
+               else {
+                       max_n = SMB_CALLOC_ARRAY(struct max_n, count);
+                       if (!max_n) {
+                               TALLOC_FREE(p);
+                               TALLOC_FREE(s);
+                               return -1;
+                       }
+                       max_n_free = max_n;
                }
        }
 
        ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive);
 
-       if (max_n) {
-               free(max_n);
-       }
-
+       SAFE_FREE(max_n_free);
+       TALLOC_FREE(p);
+       TALLOC_FREE(s);
        return ret;
 }
-
-
-/* a generic fnmatch function - uses for non-CIFS pattern matching */
-int gen_fnmatch(const char *pattern, const char *string)
-{
-       return ms_fnmatch(pattern, string, PROTOCOL_NT1, False);
-}