RIP BOOL. Convert BOOL -> bool. I found a few interesting
[nivanova/samba-autobuild/.git] / source3 / smbd / mangle_hash2.c
index 4896cfb17be86505531d1b2e3302075846d5c85e..7066c2a4e5c9ea9651dccb971ebdd5301bfa67d6 100644 (file)
@@ -6,7 +6,7 @@
    
    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,
@@ -15,8 +15,7 @@
    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/>.
 */
 
 /*
@@ -101,7 +100,7 @@ static unsigned mangle_prefix;
    hashing the resulting cache entry to match the known hash
 */
 static char **prefix_cache;
-static u32 *prefix_cache_hashes;
+static unsigned int *prefix_cache_hashes;
 
 /* these are the characters we use in the 8.3 hash. Must be 36 chars long */
 static const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -119,10 +118,10 @@ static const char *reserved_names[] =
 
    this hash needs to be fast with a low collision rate (what hash doesn't?)
 */
-static u32 mangle_hash(const char *key, unsigned int length)
+static unsigned int mangle_hash(const char *key, unsigned int length)
 {
-       u32 value;
-       u32   i;
+       unsigned int value;
+       unsigned int   i;
        fstring str;
 
        /* we have to uppercase here to ensure that the mangled name
@@ -139,8 +138,8 @@ static u32 mangle_hash(const char *key, unsigned int length)
 
        /* Set the initial value from the key size. */
        for (value = FNV1_INIT, i=0; i < length; i++) {
-                value *= (u32)FNV1_PRIME;
-                value ^= (u32)(str[i]);
+                value *= (unsigned int)FNV1_PRIME;
+                value ^= (unsigned int)(str[i]);
         }
 
        /* note that we force it to a 31 bit hash, to keep within the limits
@@ -151,7 +150,7 @@ static u32 mangle_hash(const char *key, unsigned int length)
 /* 
    initialise (ie. allocate) the prefix cache
  */
-static BOOL cache_init(void)
+static bool cache_init(void)
 {
        if (prefix_cache) {
                return True;
@@ -162,8 +161,9 @@ static BOOL cache_init(void)
                return False;
        }
 
-       prefix_cache_hashes = SMB_CALLOC_ARRAY(u32, MANGLE_CACHE_SIZE);
+       prefix_cache_hashes = SMB_CALLOC_ARRAY(unsigned int, MANGLE_CACHE_SIZE);
        if (!prefix_cache_hashes) {
+               SAFE_FREE(prefix_cache);
                return False;
        }
 
@@ -173,7 +173,7 @@ static BOOL cache_init(void)
 /*
   insert an entry into the prefix cache. The string might not be null
   terminated */
-static void cache_insert(const char *prefix, int length, u32 hash)
+static void cache_insert(const char *prefix, int length, unsigned int hash)
 {
        int i = hash % MANGLE_CACHE_SIZE;
 
@@ -188,7 +188,7 @@ static void cache_insert(const char *prefix, int length, u32 hash)
 /*
   lookup an entry in the prefix cache. Return NULL if not found.
 */
-static const char *cache_lookup(u32 hash)
+static const char *cache_lookup(unsigned int hash)
 {
        int i = hash % MANGLE_CACHE_SIZE;
 
@@ -208,11 +208,11 @@ static const char *cache_lookup(u32 hash)
    In this algorithm, mangled names use only pure ascii characters (no
    multi-byte) so we can avoid doing a UCS2 conversion 
  */
-static BOOL is_mangled_component(const char *name, size_t len)
+static bool is_mangled_component(const char *name, size_t len)
 {
        unsigned int i;
 
-       M_DEBUG(10,("is_mangled_component %s (len %u) ?\n", name, (unsigned int)len));
+       M_DEBUG(10,("is_mangled_component %s (len %lu) ?\n", name, (unsigned long)len));
 
        /* check the length */
        if (len > 12 || len < 8)
@@ -250,7 +250,7 @@ static BOOL is_mangled_component(const char *name, size_t len)
                }
        }
 
-       M_DEBUG(10,("is_mangled_component %s (len %u) -> yes\n", name, (unsigned int)len));
+       M_DEBUG(10,("is_mangled_component %s (len %lu) -> yes\n", name, (unsigned long)len));
 
        return True;
 }
@@ -268,7 +268,7 @@ static BOOL is_mangled_component(const char *name, size_t len)
    directory separators. It should return true if any component is
    mangled
  */
-static BOOL is_mangled(const char *name)
+static bool is_mangled(const char *name, const struct share_params *parm)
 {
        const char *p;
        const char *s;
@@ -293,7 +293,7 @@ static BOOL is_mangled(const char *name)
    simplifies things greatly (it means that we know the string won't
    get larger when converted from UNIX to DOS formats)
 */
-static BOOL is_8_3(const char *name, BOOL check_case, BOOL allow_wildcards)
+static bool is_8_3(const char *name, bool check_case, bool allow_wildcards, const struct share_params *p)
 {
        int len, i;
        char *dot_p;
@@ -368,25 +368,30 @@ static void mangle_reset(void)
 
 /*
   try to find a 8.3 name in the cache, and if found then
-  replace the string with the original long name. 
+  replace the string with the original long name.
 */
-static BOOL check_cache(char *name, size_t maxlen)
+static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
+                       const char *name,
+                       char **pp_out, /* talloced on the given context. */
+                       const struct share_params *p)
 {
-       u32 hash, multiplier;
+       unsigned int hash, multiplier;
        unsigned int i;
        const char *prefix;
        char extension[4];
 
+       *pp_out = NULL;
+
        /* make sure that this is a mangled name from this cache */
-       if (!is_mangled(name)) {
-               M_DEBUG(10,("check_cache: %s -> not mangled\n", name));
+       if (!is_mangled(name, p)) {
+               M_DEBUG(10,("lookup_name_from_8_3: %s -> not mangled\n", name));
                return False;
        }
 
        /* we need to extract the hash from the 8.3 name */
        hash = base_reverse[(unsigned char)name[7]];
        for (multiplier=36, i=5;i>=mangle_prefix;i--) {
-               u32 v = base_reverse[(unsigned char)name[i]];
+               unsigned int v = base_reverse[(unsigned char)name[i]];
                hash += multiplier * v;
                multiplier *= 36;
        }
@@ -394,7 +399,8 @@ static BOOL check_cache(char *name, size_t maxlen)
        /* now look in the prefix cache for that hash */
        prefix = cache_lookup(hash);
        if (!prefix) {
-               M_DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash));
+               M_DEBUG(10,("lookup_name_from_8_3: %s -> %08X -> not found\n",
+                                       name, hash));
                return False;
        }
 
@@ -407,21 +413,26 @@ static BOOL check_cache(char *name, size_t maxlen)
        }
 
        if (extension[0]) {
-               M_DEBUG(10,("check_cache: %s -> %s.%s\n", name, prefix, extension));
-               slprintf(name, maxlen, "%s.%s", prefix, extension);
+               M_DEBUG(10,("lookup_name_from_8_3: %s -> %s.%s\n",
+                                       name, prefix, extension));
+               *pp_out = talloc_asprintf(ctx, "%s.%s", prefix, extension);
        } else {
-               M_DEBUG(10,("check_cache: %s -> %s\n", name, prefix));
-               safe_strcpy(name, prefix, maxlen);
+               M_DEBUG(10,("lookup_name_from_8_3: %s -> %s\n", name, prefix));
+               *pp_out = talloc_strdup(ctx, prefix);
+       }
+
+       if (!pp_out) {
+               M_DEBUG(0,("talloc_fail"));
+               return False;
        }
 
        return True;
 }
 
-
 /*
   look for a DOS reserved name
 */
-static BOOL is_reserved_name(const char *name)
+static bool is_reserved_name(const char *name)
 {
        if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) &&
            FLAG_CHECK(name[1], FLAG_POSSIBLE2) &&
@@ -445,12 +456,13 @@ static BOOL is_reserved_name(const char *name)
 /*
  See if a filename is a legal long filename.
  A filename ending in a '.' is not legal unless it's "." or "..". JRA.
+ A filename ending in ' ' is not legal either. See bug id #2769.
 */
 
-static BOOL is_legal_name(const char *name)
+static bool is_legal_name(const char *name)
 {
        const char *dot_pos = NULL;
-       BOOL alldots = True;
+       bool alldots = True;
        size_t numdots = 0;
 
        while (*name) {
@@ -464,7 +476,7 @@ static BOOL is_legal_name(const char *name)
                         * for mb UNIX asian characters like Japanese (SJIS) here.
                         * JRA.
                         */
-                       if (convert_string(CH_UNIX, CH_UCS2, name, 2, mbc, 2, False) == 2) {
+                       if (convert_string(CH_UNIX, CH_UTF16LE, name, 2, mbc, 2, False) == 2) {
                                /* Was a good mb string. */
                                name += 2;
                                continue;
@@ -480,6 +492,10 @@ static BOOL is_legal_name(const char *name)
                } else {
                        alldots = False;
                }
+               if ((name[0] == ' ') && (name[1] == '\0')) {
+                       /* Can't end in ' ' */
+                       return False;
+               }
                name++;
        }
 
@@ -491,43 +507,45 @@ static BOOL is_legal_name(const char *name)
                if (dot_pos[1] == '\0')
                        return False;
        }
-
        return True;
 }
 
+static bool must_mangle(const char *name,
+                       const struct share_params *p)
+{
+       if (is_reserved_name(name)) {
+               return True;
+       }
+       return !is_legal_name(name);
+}
+
 /*
   the main forward mapping function, which converts a long filename to 
   a 8.3 name
 
-  if need83 is not set then we only do the mangling if the name is illegal
-  as a long name
-
   if cache83 is not set then we don't cache the result
 
-  the name parameter must be able to hold 13 bytes
 */
-static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case)
+static bool hash2_name_to_8_3(const char *name,
+                       char new_name[13],
+                       bool cache83,
+                       int default_case,
+                       const struct share_params *p)
 {
        char *dot_p;
        char lead_chars[7];
        char extension[4];
        unsigned int extension_length, i;
        unsigned int prefix_len;
-       u32 hash, v;
-       char new_name[13];
+       unsigned int hash, v;
 
        /* reserved names are handled specially */
        if (!is_reserved_name(name)) {
-               /* if the name is already a valid 8.3 name then we don't need to 
-                  do anything */
-               if (is_8_3(name, False, False)) {
-                       return;
-               }
-
-               /* if the caller doesn't strictly need 8.3 then just check for illegal 
-                  filenames */
-               if (!need83 && is_legal_name(name)) {
-                       return;
+               /* if the name is already a valid 8.3 name then we don't need to
+                * change anything */
+               if (is_legal_name(name) && is_8_3(name, False, False, p)) {
+                       safe_strcpy(new_name, name, 12);
+                       return True;
                }
        }
 
@@ -544,7 +562,9 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case)
                                break;
                        }
                }
-               if (i == 0 || i == 4) dot_p = NULL;
+               if (i == 0 || i == 4) {
+                       dot_p = NULL;
+               }
        }
 
        /* the leading characters in the mangled name is taken from
@@ -556,7 +576,7 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case)
                if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) {
                        lead_chars[i] = '_';
                }
-               lead_chars[i] = toupper(lead_chars[i]);
+               lead_chars[i] = toupper_ascii(lead_chars[i]);
        }
        for (;i<mangle_prefix;i++) {
                lead_chars[i] = '_';
@@ -576,11 +596,12 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case)
                for (i=1; extension_length < 3 && dot_p[i]; i++) {
                        char c = dot_p[i];
                        if (FLAG_CHECK(c, FLAG_ASCII)) {
-                               extension[extension_length++] = toupper(c);
+                               extension[extension_length++] =
+                                       toupper_ascii(c);
                        }
                }
        }
-          
+
        /* find the hash for this prefix */
        v = hash = mangle_hash(name, prefix_len);
 
@@ -589,7 +610,7 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case)
                new_name[i] = lead_chars[i];
        }
        new_name[7] = base_forward(v % 36);
-       new_name[6] = '~';      
+       new_name[6] = '~';
        for (i=5; i>=mangle_prefix; i--) {
                v = v / 36;
                new_name[i] = base_forward(v % 36);
@@ -609,22 +630,18 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case)
                cache_insert(name, prefix_len, hash);
        }
 
-       M_DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n", 
+       M_DEBUG(10,("hash2_name_to_8_3: %s -> %08X -> %s (cache=%d)\n",
                   name, hash, new_name, cache83));
 
-       /* and overwrite the old name */
-       fstrcpy(name, new_name);
-
-       /* all done, we've managed to mangle it */
+       return True;
 }
 
-
-/* initialise the flags table 
+/* initialise the flags table
 
   we allow only a very restricted set of characters as 'ascii' in this
   mangling backend. This isn't a significant problem as modern clients
   use the 'long' filenames anyway, and those don't have these
-  restrictions. 
+  restrictions.
 */
 static void init_tables(void)
 {
@@ -633,8 +650,13 @@ static void init_tables(void)
        memset(char_flags, 0, sizeof(char_flags));
 
        for (i=1;i<128;i++) {
-               if ((i >= '0' && i <= '9') || 
-                   (i >= 'a' && i <= 'z') || 
+               if (i <= 0x1f) {
+                       /* Control characters. */
+                       char_flags[i] |= FLAG_ILLEGAL;
+               }
+
+               if ((i >= '0' && i <= '9') ||
+                   (i >= 'a' && i <= 'z') ||
                    (i >= 'A' && i <= 'Z')) {
                        char_flags[i] |=  (FLAG_ASCII | FLAG_BASECHAR);
                }
@@ -654,7 +676,7 @@ static void init_tables(void)
        memset(base_reverse, 0, sizeof(base_reverse));
        for (i=0;i<36;i++) {
                base_reverse[(unsigned char)base_forward(i)] = i;
-       }       
+       }
 
        /* fill in the reserved names flags. These are used as a very
           fast filter for finding possible DOS reserved filenames */
@@ -670,25 +692,25 @@ static void init_tables(void)
                char_flags[c2] |= FLAG_POSSIBLE2;
                char_flags[c3] |= FLAG_POSSIBLE3;
                char_flags[c4] |= FLAG_POSSIBLE4;
-               char_flags[tolower(c1)] |= FLAG_POSSIBLE1;
-               char_flags[tolower(c2)] |= FLAG_POSSIBLE2;
-               char_flags[tolower(c3)] |= FLAG_POSSIBLE3;
-               char_flags[tolower(c4)] |= FLAG_POSSIBLE4;
+               char_flags[tolower_ascii(c1)] |= FLAG_POSSIBLE1;
+               char_flags[tolower_ascii(c2)] |= FLAG_POSSIBLE2;
+               char_flags[tolower_ascii(c3)] |= FLAG_POSSIBLE3;
+               char_flags[tolower_ascii(c4)] |= FLAG_POSSIBLE4;
 
                char_flags[(unsigned char)'.'] |= FLAG_POSSIBLE4;
        }
 }
 
-
 /*
   the following provides the abstraction layer to make it easier
   to drop in an alternative mangling implementation */
 static struct mangle_fns mangle_fns = {
+       mangle_reset,
        is_mangled,
+       must_mangle,
        is_8_3,
-       mangle_reset,
-       check_cache,
-       name_map
+       lookup_name_from_8_3,
+       hash2_name_to_8_3
 };
 
 /* return the methods for this mangling implementation */
@@ -712,3 +734,57 @@ struct mangle_fns *mangle_hash2_init(void)
 
        return &mangle_fns;
 }
+
+static void posix_mangle_reset(void)
+{;}
+
+static bool posix_is_mangled(const char *s, const struct share_params *p)
+{
+       return False;
+}
+
+static bool posix_must_mangle(const char *s, const struct share_params *p)
+{
+       return False;
+}
+
+static bool posix_is_8_3(const char *fname,
+                       bool check_case,
+                       bool allow_wildcards,
+                       const struct share_params *p)
+{
+       return False;
+}
+
+static bool posix_lookup_name_from_8_3(TALLOC_CTX *ctx,
+                               const char *in,
+                               char **out, /* talloced on the given context. */
+                               const struct share_params *p)
+{
+       return False;
+}
+
+static bool posix_name_to_8_3(const char *in,
+                               char out[13],
+                               bool cache83,
+                               int default_case,
+                               const struct share_params *p)
+{
+       memset(out, '\0', 13);
+       return True;
+}
+
+/* POSIX paths backend - no mangle. */
+static struct mangle_fns posix_mangle_fns = {
+       posix_mangle_reset,
+       posix_is_mangled,
+       posix_must_mangle,
+       posix_is_8_3,
+       posix_lookup_name_from_8_3,
+       posix_name_to_8_3
+};
+
+struct mangle_fns *posix_mangle_init(void)
+{
+       return &posix_mangle_fns;
+}