Reintroduce the 2.2 name mangling code, until we get are more flexible solution.
authorAndrew Bartlett <abartlet@samba.org>
Mon, 8 Apr 2002 01:58:44 +0000 (01:58 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 8 Apr 2002 01:58:44 +0000 (01:58 +0000)
Even for a hash/cache setup, this code needs some more work, in particular
it needs to use mangle_get_prefix() etc and to move to unicode internals.

Andrew Bartlett

source/smbd/filename.c
source/smbd/mangle.c
source/smbd/reply.c
source/smbd/server.c

index 3053e8a1d817c02b6cb5d02a18927fd5708785a4..8bd09691e4f994c07a39b6c2146b5240f7683db0 100644 (file)
@@ -75,6 +75,17 @@ static BOOL fname_equal(char *name1, char *name2)
 ****************************************************************************/
 static BOOL mangled_equal(char *name1, char *name2)
 {
+#if 1
+       pstring tmpname;
+       if (is_8_3(name2, True)) {
+               return False;
+       }
+       
+       pstrcpy(tmpname, name2);
+       mangle_name_83(tmpname);
+
+       return strequal(name1, tmpname);
+#else  
        char *tmpname;
        BOOL ret = False;
 
@@ -86,6 +97,8 @@ static BOOL mangled_equal(char *name1, char *name2)
                SAFE_FREE(tmpname);
        }
        return ret;
+#endif
+       
 }
 
 
@@ -116,7 +129,7 @@ stat struct will be filled with zeros (and this can be detected by checking
 for nlinks = 0, which can never be true for any file).
 ****************************************************************************/
 
-BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, 
+BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_component, 
                   BOOL *bad_path, SMB_STRUCT_STAT *pst)
 {
   SMB_STRUCT_STAT st;
index cfa71e3cf49e3f94d9a19364fe1983e29b80c908..9789f06e0cfd962dbc7af957d4658dfdaf9382ec 100644 (file)
@@ -1,6 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
-   Name mangling with persistent tdb
+   Name mangling
+   Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Simo Sorce 2001
    Copyright (C) Andrew Bartlett 2002
    
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/****************************************************************************
-  Rewritten from scrach in 2001 by Simo Sorce <idra@samba.org>
- ****************************************************************************/
+/* -------------------------------------------------------------------------- **
+ * Notable problems...
+ *
+ *  March/April 1998  CRH
+ *  - Many of the functions in this module overwrite string buffers passed to
+ *    them.  This causes a variety of problems and is, generally speaking,
+ *    dangerous and scarry.  See the kludge notes in name_map_mangle()
+ *    below.
+ *  - It seems that something is calling name_map_mangle() twice.  The
+ *    first call is probably some sort of test.  Names which contain
+ *    illegal characters are being doubly mangled.  I'm not sure, but
+ *    I'm guessing the problem is in server.c.
+ *
+ * -------------------------------------------------------------------------- **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * History...
+ *
+ *  March/April 1998  CRH
+ *  Updated a bit.  Rewrote is_mangled() to be a bit more selective.
+ *  Rewrote the mangled name cache.  Added comments here and there.
+ *  &c.
+ * -------------------------------------------------------------------------- **
+ */
 
 #include "includes.h"
 
 extern int case_default;    /* Are conforming 8.3 names all upper or lower?   */
 extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
 
+/* -------------------------------------------------------------------------- **
+ * Other stuff...
+ *
+ * magic_char     - This is the magic char used for mangling.  It's
+ *                  global.  There is a call to lp_magicchar() in server.c
+ *                  that is used to override the initial value.
+ *
+ * MANGLE_BASE    - This is the number of characters we use for name mangling.
+ *
+ * basechars      - The set characters used for name mangling.  This
+ *                  is static (scope is this file only).
+ *
+ * mangle()       - Macro used to select a character from basechars (i.e.,
+ *                  mangle(n) will return the nth digit, modulo MANGLE_BASE).
+ *
+ * chartest       - array 0..255.  The index range is the set of all possible
+ *                  values of a byte.  For each byte value, the content is a
+ *                  two nibble pair.  See BASECHAR_MASK and ILLEGAL_MASK,
+ *                  below.
+ *
+ * ct_initialized - False until the chartest array has been initialized via
+ *                  a call to init_chartest().
+ *
+ * BASECHAR_MASK  - Masks the upper nibble of a one-byte value.
+ *
+ * ILLEGAL_MASK   - Masks the lower nibble of a one-byte value.
+ *
+ * isbasecahr()   - Given a character, check the chartest array to see
+ *                  if that character is in the basechars set.  This is
+ *                  faster than using strchr_m().
+ *
+ * isillegal()    - Given a character, check the chartest array to see
+ *                  if that character is in the illegal characters set.
+ *                  This is faster than using strchr_m().
+ *
+ * mangled_cache  - Cache header used for storing mangled -> original
+ *                  reverse maps.
+ *
+ * mc_initialized - False until the mangled_cache structure has been
+ *                  initialized via a call to reset_mangled_cache().
+ *
+ * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
+ *                  cache.  A value of 0 indicates "infinite".
+ *
+ * MANGLED_CACHE_MAX_MEMORY  - Default maximum amount of memory for the
+ *                  cache.  When the cache was kept as an array of 256
+ *                  byte strings, the default cache size was 50 entries.
+ *                  This required a fixed 12.5Kbytes of memory.  The
+ *                  mangled stack parameter is no longer used (though
+ *                  this might change).  We're now using a fixed 16Kbyte
+ *                  maximum cache size.  This will probably be much more
+ *                  than 50 entries.
+ */
+
 char magic_char = '~';
 
-/* -------------------------------------------------------------------- */
+static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
+#define MANGLE_BASE       (sizeof(basechars)/sizeof(char)-1)
 
-#define MANGLE_TDB_VERSION             "20010927"
-#define MANGLE_TDB_FILE_NAME           "mangle.tdb"
-#define MANGLED_PREFIX                 "MANGLED_"
-#define LONG_PREFIX                    "LONG_"
-#define COUNTER_PREFIX                 "COUNTER_"
-#define        MANGLE_COUNTER_MAX              99
-#define MANGLE_SUFFIX_SIZE             3 /* "~XX" */
+static unsigned char chartest[256]  = { 0 };
+static BOOL          ct_initialized = False;
 
+#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
+#define BASECHAR_MASK 0xf0
+#define ILLEGAL_MASK  0x0f
+#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
+#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
 
-static TDB_CONTEXT     *mangle_tdb;
+static ubi_cacheRoot mangled_cache[1] =  { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
+static BOOL          mc_initialized   = False;
+#define MANGLED_CACHE_MAX_ENTRIES 0
+#define MANGLED_CACHE_MAX_MEMORY  16384
 
-BOOL init_mangle_tdb(void)
-{
-       char *tdbfile;
-       
-       tdbfile = lock_path(MANGLE_TDB_FILE_NAME); /* this return a static pstring do not try to free it */
 
-       /* Open tdb */
-       if (!(mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600)))
-       {
-               DEBUG(0, ("Unable to open Mangle TDB\n"));
-               return False;
-       }
+/* -------------------------------------------------------------------------- **
+ * External Variables...
+ */
 
-       return True;
-}
+extern int case_default;    /* Are conforming 8.3 names all upper or lower?   */
+extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
 
-/* trasform a unicode string into a dos charset string */
-static int ucs2_to_dos(char *dest, const smb_ucs2_t *src, int dest_len)
-{
-       int src_len, ret;
+/* -------------------------------------------------------------------- */
 
-       if (dest_len == -1) {
-               dest_len = sizeof(pstring);
-       }
+NTSTATUS has_valid_chars(const smb_ucs2_t *s)
+{
+       if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
 
-       src_len = strlen_w(src)* sizeof(smb_ucs2_t);
+       DEBUG(10,("has_valid_chars: testing\n")); /* [%s]\n", s)); */
        
-       ret = convert_string(CH_UCS2, CH_DOS, src, src_len, dest, dest_len);
-       if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
-
-       return ret;
-}
-
-/* trasform in a string that contain only valid chars for win filenames,
- not including a '.' */
-static void strvalid(smb_ucs2_t *src)
-{
-       if (!src || !*src) return;
+       /* CHECK: this should not be necessary if the ms wild chars
+          are not valid in valid.dat  --- simo */
+       if (ms_has_wild_w(s)) return NT_STATUS_UNSUCCESSFUL;
 
-       while (*src) {
-               if (!isvalid83_w(*src) || *src == UCS2_CHAR('.')) *src = UCS2_CHAR('_');
-               src++;
+       while (*s) {
+               if(!isvalid83_w(*s)) return NT_STATUS_UNSUCCESSFUL;
+               s++;
        }
-}
 
+       return NT_STATUS_OK;
+}
 
 /* return False if something fail and
  * return 2 alloced unicode strings that contain prefix and extension
@@ -128,523 +191,18 @@ static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **pr
        return NT_STATUS_OK;
 }
 
-
-/* mangled must contain only the file name, not a path.
-   and MUST be ZERO terminated */
-smb_ucs2_t *unmangle(const smb_ucs2_t *mangled)
-{
-       TDB_DATA data, key;
-       fstring keystr;
-       fstring mufname;
-       smb_ucs2_t *pref, *ext, *retstr;
-       size_t long_len, ext_len, muf_len;
-
-       if (strlen_w(mangled) > 12) return NULL;
-       if (!strchr_w(mangled, UCS2_CHAR('~'))) return NULL;
-
-       /* if it is a path refuse to proceed */
-       if (strchr_w(mangled, UCS2_CHAR('/'))) {
-               DEBUG(10, ("unmangle: cannot unmangle a path\n"));
-               return NULL;
-       }
-
-       if (NT_STATUS_IS_ERR(mangle_get_prefix(mangled, &pref, &ext)))
-               return NULL;
-
-       /* mangled names are stored lowercase only */   
-       strlower_w(pref);
-       /* set search key */
-       muf_len = ucs2_to_dos(mufname, pref, sizeof(mufname));
-       SAFE_FREE(pref);
-       if (!muf_len) return NULL;
-       
-       slprintf(keystr, sizeof(keystr) - 1, "%s%s", MANGLED_PREFIX, mufname);
-       key.dptr = keystr;
-       key.dsize = strlen (keystr) + 1;
-       
-       /* get the record */
-       data = tdb_fetch(mangle_tdb, key);
-       
-       if (!data.dptr) /* not found */
-       {
-               DEBUG(5,("unmangle: failed retrieve from db %s\n", tdb_errorstr(mangle_tdb)));
-               retstr = NULL;
-               goto done;
-       }
-
-       if (ext)
-       {
-               long_len = (data.dsize / 2) - 1;
-               ext_len = strlen_w(ext);
-               retstr = (smb_ucs2_t *)malloc((long_len + ext_len + 2)*sizeof(smb_ucs2_t));
-               if (!retstr)
-               {
-                       DEBUG(0, ("unamngle: out of memory!\n"));
-                       goto done;
-               }
-               strncpy_w(retstr, (smb_ucs2_t *)data.dptr, long_len);
-               retstr[long_len] = UCS2_CHAR('.');
-               retstr[long_len + 1] = 0;
-               strncat_w(retstr, ext, ext_len);
-       }
-       else
-       {
-               retstr = strdup_w((smb_ucs2_t *)data.dptr);
-               if (!retstr)
-               {
-                       DEBUG(0, ("unamngle: out of memory!\n"));
-                       goto done;
-               }
-
-       }
-
-done:
-       SAFE_FREE(data.dptr);
-       SAFE_FREE(pref);
-       SAFE_FREE(ext);
-
-       return retstr;
-}
-
-/* unmangled must contain only the file name, not a path.
-   and MUST be ZERO terminated.
-   return a new allocated string if the name is yet valid 8.3
-   or is mangled successfully.
-   return null on error.
+/* ************************************************************************** **
+ * Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name.
+ *
+ *  Input:  fname - String containing the name to be tested.
+ *
+ *  Output: NT_STATUS_UNSUCCESSFUL, if the name matches one of the list of reserved names.
+ *
+ *  Notes:  This is a static function called by is_8_3(), below.
+ *
+ * ************************************************************************** **
  */
-
-smb_ucs2_t *mangle(const smb_ucs2_t *unmangled)
-{
-       TDB_DATA data, key, klock;
-       pstring keystr;
-       pstring longname;
-       fstring keylock;
-       fstring mufname;
-       fstring prefix;
-       BOOL tclock = False;
-       char suffix[7];
-       smb_ucs2_t *mangled = NULL;
-       smb_ucs2_t *umpref, *ext, *p = NULL;
-       size_t pref_len, ext_len, ud83_len;
-
-       /* if it is a path refuse to proceed */
-       if (strchr_w(unmangled, UCS2_CHAR('/'))) {
-               DEBUG(10, ("mangle: cannot mangle a path\n"));
-               return NULL;
-       }
-
-       /* if it is a valid 8_3 do not mangle again */
-       if (NT_STATUS_IS_OK(is_8_3_w(unmangled)))
-               return NULL;
-
-       if (NT_STATUS_IS_ERR(mangle_get_prefix(unmangled, &umpref, &ext)))
-               return NULL;
-
-       /* test if the same is yet mangled */
-
-       /* set search key */
-       pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
-       slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
-       key.dptr = keystr;
-       key.dsize = strlen(keystr) + 1;
-
-       /* get the record */
-       data = tdb_fetch (mangle_tdb, key);
-       if (!data.dptr) /* not found */
-       {
-               smb_ucs2_t temp[9];
-               size_t c, pos;
-
-               if (tdb_error(mangle_tdb) != TDB_ERR_NOEXIST)
-               {
-                       DEBUG(0, ("mangle: database retrieval error: %s\n",
-                                       tdb_errorstr(mangle_tdb)));
-                       goto done;
-               }
-
-               /* if not find the first free possibile mangled name */
-
-               pos = strlen_w(umpref);
-               if ((8 - MANGLE_SUFFIX_SIZE) < pos)
-                       pos = 8 - MANGLE_SUFFIX_SIZE;
-               pos++;
-               do
-               {
-                       pos--;
-                       if (pos == 0)
-                       {
-                               char *unmangled_unix = acnv_u2ux(unmangled);
-
-                               DEBUG(0, ("mangle: unable to mangle file name (%s)!\n",unmangled_unix));
-                               SAFE_FREE(unmangled_unix);
-                               goto done;
-                       }
-                       strncpy_w(temp, umpref, pos);
-                       temp[pos] = 0;
-                       strlower_w(temp);
-
-                       /* convert any invalid char into '_' */
-                       strvalid(temp);
-                       ud83_len = ucs2_to_dos(prefix, temp, sizeof(prefix));
-                       if (!ud83_len) goto done;
-               }
-               while (ud83_len > 8 - MANGLE_SUFFIX_SIZE);
-
-               slprintf(keylock, sizeof(keylock)-1, "%s%s", COUNTER_PREFIX, prefix);
-               klock.dptr = keylock;
-               klock.dsize = strlen(keylock) + 1;
-
-               c = 0;
-               data.dptr = (char *)&c;
-               data.dsize = sizeof(uint32);
-               /* try to insert a new counter prefix, if it exist the call will
-                  fail (correct) otherwise it will create a new entry with counter set
-                  to 0
-                */
-               if(tdb_store(mangle_tdb, klock, data, TDB_INSERT) != TDB_SUCCESS)
-               {
-                       if (tdb_error(mangle_tdb) != TDB_ERR_EXISTS)
-                       {
-                               char *unmangled_unix = acnv_u2ux(unmangled);
-                               DEBUG(0, ("mangle: database store error: %s for filename: %s\n",
-                                       tdb_errorstr(mangle_tdb), unmangled_unix));
-                               SAFE_FREE(unmangled_unix);
-                               goto done;
-                       }
-               }
-
-               /* lock the mangle counter for this prefix */           
-               if (tdb_chainlock(mangle_tdb, klock))
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-
-                       DEBUG(0,("mangle: failed to lock database for filename %s\n!", unmangled_unix));
-                       SAFE_FREE(unmangled_unix);
-                       goto done;
-               }
-               tclock = True;
-
-               data = tdb_fetch(mangle_tdb, klock);
-               if (!data.dptr)
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-
-                       DEBUG(0, ("mangle: database retrieval error: %s for filename: %s\n",
-                                 tdb_errorstr(mangle_tdb), unmangled_unix));
-                       SAFE_FREE(unmangled_unix);
-                       goto done;
-               }
-               c = *((uint32 *)data.dptr);
-               c++;
-               
-               if (c > MANGLE_COUNTER_MAX)
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-
-                       DEBUG(0, ("mangle: error, counter overflow (max=%d, counter=%d) for file: [%s] prefix (dos charset): [%s]!\n", MANGLE_COUNTER_MAX, c, unmangled_unix, prefix));
-                       SAFE_FREE(unmangled_unix);
-                       goto done;
-               }
-                       
-               temp[pos] = UCS2_CHAR('~');
-               temp[pos+1] = 0;
-               snprintf(suffix, 7, "%.6d", c);
-               strncat_wa(temp, &suffix[7 - MANGLE_SUFFIX_SIZE], MANGLE_SUFFIX_SIZE);
-
-               ud83_len = ucs2_to_dos(mufname, temp, sizeof(mufname));
-               if (!ud83_len) goto done;
-               if (ud83_len > 8)
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-
-                       DEBUG(0, ("mangle: darn, logic error aborting!  Filename was %s\n", unmangled_unix));
-                       SAFE_FREE(unmangled_unix);
-                       goto done;
-               }
-                       
-               /* store the long entry with mangled key */
-               slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
-               key.dptr = keystr;
-               key.dsize = strlen (keystr) + 1;
-               data.dsize = (strlen_w(umpref) + 1) * sizeof (smb_ucs2_t);
-               data.dptr = (void *)umpref;
-
-               if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-
-                       DEBUG(0, ("mangle: database store error: %s for filename: %s\n",
-                                       tdb_errorstr(mangle_tdb), unmangled_unix));
-                       SAFE_FREE(unmangled_unix);
-                       goto done;
-               }
-
-               /* store the mangled entry with long key*/
-               pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
-               slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
-               key.dptr = keystr;
-               key.dsize = strlen (keystr) + 1;
-               data.dsize = strlen(mufname) + 1;
-               data.dptr = mufname;
-               if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-                       DEBUG(0, ("mangle: database store failed: %s for filename: %s\n",
-                                       tdb_errorstr(mangle_tdb), unmangled_unix));
-                       SAFE_FREE(unmangled_unix);
-
-                       /* try to delete the mangled key entry to avoid later inconsistency */
-                       slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
-                       key.dptr = keystr;
-                       key.dsize = strlen (keystr) + 1;
-                       if (!tdb_delete(mangle_tdb, key))
-                       {
-                               DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
-                       }
-                       goto done;
-               }
-
-               p = strdup_w(temp);
-               if (!p)
-               {
-                       DEBUG(0,("mangle: out of memory!\n"));
-                       goto done;
-               }
-               
-               data.dptr = (char *)&c;
-               data.dsize = sizeof(uint32);
-               /* store the counter */
-               if(tdb_store(mangle_tdb, klock, data, TDB_REPLACE) != TDB_SUCCESS)
-               {
-                       char *unmangled_unix = acnv_u2ux(unmangled);
-                       DEBUG(0, ("mangle: database store failed: %s for filename: %s\n", 
-                                       tdb_errorstr(mangle_tdb), unmangled_unix));
-                       SAFE_FREE(unmangled_unix);
-                       /* try to delete the mangled and long key entry to avoid later inconsistency */
-                       slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
-                       key.dptr = keystr;
-                       key.dsize = strlen (keystr) + 1;
-                       if (!tdb_delete(mangle_tdb, key))
-                       {
-                               DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
-                       }
-                       slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
-                       key.dptr = keystr;
-                       key.dsize = strlen (keystr) + 1;
-                       if (!tdb_delete(mangle_tdb, key))
-                       {
-                               DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
-                       }
-                       goto done;
-               }
-
-               tclock = False;
-               tdb_chainunlock(mangle_tdb, klock);
-       }
-       else /* FOUND */
-       {
-               p = acnv_dosu2(data.dptr);
-               if (!p)
-               {
-                       DEBUG(0,("mangle: internal error acnv_dosu2() failed!\n"));
-                       goto done;
-               }
-       }
-               
-       if (ext)
-       {
-               pref_len = strlen_w(p);
-               ext_len = strlen_w(ext);
-               mangled = (smb_ucs2_t *)malloc((pref_len + ext_len + 2)*sizeof(smb_ucs2_t));
-               if (!mangled)
-               {
-                       DEBUG(0,("mangle: out of memory!\n"));
-                       goto done;
-               }
-               strncpy_w (mangled, p, pref_len);
-               mangled[pref_len] = UCS2_CHAR('.');
-               mangled[pref_len + 1] = 0;
-               strncat_w (mangled, ext, ext_len);
-       }
-       else
-       {
-               mangled = strdup_w(p);
-               if (!mangled)
-               {
-                       DEBUG(0,("mangle: out of memory!\n"));
-                       goto done;
-               }
-       }
-
-       /* mangled name are returned in upper or lower case depending on
-          case_default value */
-       strnorm_w(mangled);
-
-done:
-       if (tclock) tdb_chainunlock(mangle_tdb, klock);
-       SAFE_FREE(p);
-       SAFE_FREE(umpref);
-       SAFE_FREE(ext);
-
-       return mangled;
-}
-
-
-/* non unicode compatibility functions */
-
-char *dos_mangle(const char *dos_unmangled)
-{
-       smb_ucs2_t *in, *out;
-       char *dos_mangled;
-
-       if (!dos_unmangled || !*dos_unmangled) return NULL;
-
-       in = acnv_dosu2(dos_unmangled);
-       if (!in)
-       {
-               DEBUG(0,("dos_mangle: internal error acnv_dosu2() failed!\n"));
-               return NULL;
-       }
-
-       out = mangle(in);
-       if (!out)
-       {
-               SAFE_FREE(in);
-               return NULL;
-       }
-
-       dos_mangled = acnv_u2dos(out);
-       if (!dos_mangled)
-       {
-               DEBUG(0,("dos_mangle: internal error acnv_u2dos() failed!\n"));
-               goto done;
-       }
-
-done:
-       SAFE_FREE(in);
-       SAFE_FREE(out);
-       return dos_mangled;
-}
-
-char *dos_unmangle(const char *dos_mangled)
-{
-       smb_ucs2_t *in, *out;
-       char *dos_unmangled;
-
-       if (!dos_mangled || !*dos_mangled) return NULL;
-
-       in = acnv_dosu2(dos_mangled);
-       if (!in)
-       {
-               DEBUG(0,("dos_unmangle: internal error acnv_dosu2() failed!\n"));
-               return NULL;
-       }
-
-       out = unmangle(in);
-       if (!out)
-       {
-               SAFE_FREE(in);
-               return NULL;
-       }
-
-       dos_unmangled = acnv_u2dos(out);
-       if (!dos_unmangled)
-       {
-               DEBUG(0,("dos_unmangle: internal error acnv_u2dos failed!\n"));
-               goto done;
-       }
-
-done:
-       SAFE_FREE(in);
-       SAFE_FREE(out);
-       return dos_unmangled;
-}
-
-BOOL is_8_3(const char *fname, BOOL check_case)
-{
-       const char *f;
-       smb_ucs2_t *ucs2name;
-       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
-       if (!fname || !*fname) return False;
-       if ((f = strrchr(fname, '/')) == NULL) f = fname;
-       else f++;
-
-       DEBUG(10,("is_8_3: testing [%s]\n", f));
-
-       if (strlen(f) > 12) return False;
-       
-       ucs2name = acnv_uxu2(f);
-       if (!ucs2name)
-       {
-               DEBUG(0,("is_8_3: internal error acnv_uxu2() failed!\n"));
-               goto done;
-       }
-
-       ret = is_8_3_w(ucs2name);
-
-done:
-       SAFE_FREE(ucs2name);
-
-       DEBUG(10,("is_8_3: returning -> %s\n", NT_STATUS_IS_OK(ret)?"True":"False"));
-
-       if (NT_STATUS_IS_ERR(ret)) return False;
-       else return True;
-}
-
-NTSTATUS is_8_3_w(const smb_ucs2_t *fname)
-{
-       smb_ucs2_t *pref = 0, *ext = 0;
-       size_t plen;
-       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
-       if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
-
-       DEBUG(10,("is_8_3_w: testing\n")); /* [%s]\n", fname)); */
-
-       if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL;
-       
-       if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
-               return NT_STATUS_OK;
-
-       if (NT_STATUS_IS_ERR(is_valid_name(fname))) goto done;
-
-       if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext))) goto done;
-       plen = strlen_w(pref);
-
-       if (strchr_wa(pref, '.')) goto done;
-       if (plen < 1 || plen > 8) goto done;
-       if (ext) if (strlen_w(ext) > 3) goto done;
-
-       ret = NT_STATUS_OK;
-
-done:
-       SAFE_FREE(pref);
-       SAFE_FREE(ext);
-       return ret;
-}
-
-NTSTATUS has_valid_chars(const smb_ucs2_t *s)
-{
-       NTSTATUS ret = NT_STATUS_OK;
-
-       if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
-
-       DEBUG(10,("has_valid_chars: testing\n")); /* [%s]\n", s)); */
-       
-       /* CHECK: this should not be necessary if the ms wild chars
-          are not valid in valid.dat  --- simo */
-       if (ms_has_wild_w(s)) return NT_STATUS_UNSUCCESSFUL;
-
-       while (*s) {
-               if(!isvalid83_w(*s)) return NT_STATUS_UNSUCCESSFUL;
-               s++;
-       }
-
-       return ret;
-}
-
-NTSTATUS is_valid_name(const smb_ucs2_t *fname)
+static NTSTATUS is_valid_name(const smb_ucs2_t *fname)
 {
        smb_ucs2_t *str, *p;
        NTSTATUS ret = NT_STATUS_OK;
@@ -703,296 +261,703 @@ NTSTATUS is_valid_name(const smb_ucs2_t *fname)
        return ret;
 }
 
-BOOL is_mangled(const char *s)
-{
-       smb_ucs2_t *u2, *res;
-       BOOL ret = False;
-       
-       DEBUG(10,("is_mangled: testing [%s]\n", s));
-       
-       if (!s || !*s) return False;
-       if ((strlen(s) > 12) || (!strchr(s, '~'))) return False;
-       
-       u2 = acnv_dosu2(s);
-       if (!u2)
-       {
-               DEBUG(0,("is_mangled: internal error acnv_dosu2() failed!!\n"));
-               return ret;
-       }
-
-       res = unmangle(u2);
-       if (res) ret = True;
-       SAFE_FREE(res);
-       SAFE_FREE(u2);
-       DEBUG(10,("is_mangled: returning  [%s]\n", ret?"True":"False"));
-       return ret;
-}
-
-NTSTATUS is_mangled_w(const smb_ucs2_t *s)
-{
-       smb_ucs2_t *res;
-       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-       
-       res = unmangle(s);
-       if (res) ret = NT_STATUS_OK;
-       SAFE_FREE(res);
-       return ret;
-}
-
-NTSTATUS path_has_mangled(const smb_ucs2_t *s)
+static NTSTATUS is_8_3_w(const smb_ucs2_t *fname)
 {
-       smb_ucs2_t *p, *f, *b;
+       smb_ucs2_t *pref = 0, *ext = 0;
+       size_t plen;
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
 
-       if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
-
-       p = strdup_w(s);
-       if (!p) return NT_STATUS_NO_MEMORY;
-       trim_string_wa(p, "/", "/");
-       f = b = p;
-       while (b) {
-               b = strchr_w(f, UCS2_CHAR('/'));
-               if (b) *b = 0;
-               if (NT_STATUS_IS_OK(is_mangled_w(f))) {
-                       ret = NT_STATUS_OK;
-                       goto done;
-               }
-               f = b + 1;
-       }
-done:
-       SAFE_FREE(p);
-       return ret;
-}
+       if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
 
-/* backward compatibility functions */
+       DEBUG(10,("is_8_3_w: testing\n")); /* [%s]\n", fname)); */
 
-void reset_mangled_cache(void)
-{
-       DEBUG(10,("reset_mangled_cache: compatibility function, remove me!\n"));
-}
+       if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL;
+       
+       if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
+               return NT_STATUS_OK;
 
-BOOL check_mangled_cache(char *s)
-{
-       smb_ucs2_t *u2, *res;
-       BOOL ret = False;
+       if (NT_STATUS_IS_ERR(is_valid_name(fname))) goto done;
 
-       DEBUG(10,("check_mangled_cache: I'm so ugly, please remove me!\n"));
-       DEBUG(10,("check_mangled_cache: testing -> [%s]\n", s));
+       if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext))) goto done;
+       plen = strlen_w(pref);
 
-       if (!s || !*s) return False;
+       if (strchr_wa(pref, '.')) goto done;
+       if (plen < 1 || plen > 8) goto done;
+       if (ext) if (strlen_w(ext) > 3) goto done;
 
-       u2 = acnv_dosu2(s);
-       if (!u2)
-       {
-               DEBUG(0,("check_mangled_cache: out of memory!\n"));
-               return ret;
-       }
+       ret = NT_STATUS_OK;
 
-       res = unmangle(u2);
-       if (res)
-       {
-               
-               ucs2_to_dos (s, res, PSTRING_LEN);
-               /* We MUST change this brainded interface,
-                  we do not know how many chars will be used
-                  in dos so i guess they will be no more than
-                  double the size of the unicode string
-                         ---simo */
-               DEBUG(10,("check_mangled_cache: returning -> [%s]\n", s));
-               ret = True;
-       }
-       SAFE_FREE(res);
-       SAFE_FREE(u2);
-       DEBUG(10,("check_mangled_cache: returning -> %s\n", ret?"True":"False"));
+done:
+       SAFE_FREE(pref);
+       SAFE_FREE(ext);
        return ret;
 }
 
-void mangle_name_83(char *s)
+BOOL is_8_3(const char *fname, BOOL check_case)
 {
-       smb_ucs2_t *u2, *res;
+       const char *f;
+       smb_ucs2_t *ucs2name;
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
 
-       DEBUG(10,("mangle_name_83: I'm so ugly, please remove me!\n"));
-       DEBUG(10,("mangle_name_83: testing -> [%s]\n", s));
+       if (!fname || !*fname) return False;
+       if ((f = strrchr(fname, '/')) == NULL) f = fname;
+       else f++;
 
-       if (!s || !*s) return;
+       DEBUG(10,("is_8_3: testing [%s]\n", f));
+
+       if (strlen(f) > 12) return False;
        
-       u2 = acnv_dosu2(s);
-       if (!u2)
+       ucs2name = acnv_uxu2(f);
+       if (!ucs2name)
        {
-               DEBUG(0,("mangle_name_83: internal error acnv_dosu2() failed!\n"));
-               return;
+               DEBUG(0,("is_8_3: internal error acnv_uxu2() failed!\n"));
+               goto done;
        }
 
-       res = mangle(u2);
-       if (res) ucs2_to_dos (s, res, 13); /* ugly, but must be done this way */
-       DEBUG(10,("mangle_name_83: returning -> [%s]\n", s));
-       SAFE_FREE(res);
-       SAFE_FREE(u2);
-}
+       ret = is_8_3_w(ucs2name);
 
-BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
-{
-       DEBUG(10,("name_map_mangle: I'm so ugly, please remove me!\n"));
+done:
+       SAFE_FREE(ucs2name);
 
-       if (!need83) return True;
-       /* if (is_8_3(OutName, True)) return True; */
-       /* Warning: we should check for invalid chars in file name and mangle
-          if invalid chars found --simo*/
+       DEBUG(10,("is_8_3: returning -> %s\n", NT_STATUS_IS_OK(ret)?"True":"False"));
 
-       mangle_name_83(OutName);
+       if (!NT_STATUS_IS_OK(ret)) { 
+               return False;
+       }
+       
        return True;
 }
 
 
 
-#if 0 /* TEST_MANGLE_CODE */
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
 
-#define LONG           "this_is_a_long_file_name"
-#define        LONGM           "this_~01"
-#define SHORT          "short"
-#define        SHORTM          "short~01"
-#define EXT1           "ex1"
-#define EXT2           "e2"
-#define EXT3           "3"
-#define EXTFAIL                "longext"
-#define EXTNULL                ""
+/* ************************************************************************** **
+ * Initialize the static character test array.
+ *
+ *  Input:  none
+ *
+ *  Output: none
+ *
+ *  Notes:  This function changes (loads) the contents of the <chartest>
+ *          array.  The scope of <chartest> is this file.
+ *
+ * ************************************************************************** **
+ */
+static void init_chartest( void )
+  {
+  char          *illegalchars = "*\\/?<>|\":";
+  unsigned char *s;
+  
+  memset( (char *)chartest, '\0', 256 );
+
+  for( s = (unsigned char *)illegalchars; *s; s++ )
+    chartest[*s] = ILLEGAL_MASK;
+
+  for( s = (unsigned char *)basechars; *s; s++ )
+    chartest[*s] |= BASECHAR_MASK;
+
+  ct_initialized = True;
+  } /* init_chartest */
+
+
+/* ************************************************************************** **
+ * Return True if the name *could be* a mangled name.
+ *
+ *  Input:  s - A path name - in UNIX pathname format.
+ *
+ *  Output: True if the name matches the pattern described below in the
+ *          notes, else False.
+ *
+ *  Notes:  The input name is *not* tested for 8.3 compliance.  This must be
+ *          done separately.  This function returns true if the name contains
+ *          a magic character followed by excactly two characters from the
+ *          basechars list (above), which in turn are followed either by the
+ *          nul (end of string) byte or a dot (extension) or by a '/' (end of
+ *          a directory name).
+ *
+ * ************************************************************************** **
+ */
+BOOL is_mangled( char *s )
+  {
+  char *magic;
+
+  if( !ct_initialized )
+    init_chartest();
+
+  magic = strchr_m( s, magic_char );
+  while( magic && magic[1] && magic[2] )          /* 3 chars, 1st is magic. */
+    {
+    if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
+     && isbasechar( toupper(magic[1]) )           /* is 2nd char basechar?  */
+     && isbasechar( toupper(magic[2]) ) )         /* is 3rd char basechar?  */
+      return( True );                           /* If all above, then true, */
+    magic = strchr_m( magic+1, magic_char );      /*    else seek next magic. */
+    }
+  return( False );
+  } /* is_mangled */
+
+
+/* ************************************************************************** **
+ * Compare two cache keys and return a value indicating their ordinal
+ * relationship.
+ *
+ *  Input:  ItemPtr - Pointer to a comparison key.  In this case, this will
+ *                    be a mangled name string.
+ *          NodePtr - Pointer to a node in the cache.  The node structure
+ *                    will be followed in memory by a mangled name string.
+ *
+ *  Output: A signed integer, as follows:
+ *            (x < 0)  <==> Key1 less than Key2
+ *            (x == 0) <==> Key1 equals Key2
+ *            (x > 0)  <==> Key1 greater than Key2
+ *
+ *  Notes:  This is a ubiqx-style comparison routine.  See ubi_BinTree for
+ *          more info.
+ *
+ * ************************************************************************** **
+ */
+static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
+  {
+  char *Key1 = (char *)ItemPtr;
+  char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
+
+  return( StrCaseCmp( Key1, Key2 ) );
+  } /* cache_compare */
+
+/* ************************************************************************** **
+ * Free a cache entry.
+ *
+ *  Input:  WarrenZevon - Pointer to the entry that is to be returned to
+ *                        Nirvana.
+ *  Output: none.
+ *
+ *  Notes:  This function gets around the possibility that the standard
+ *          free() function may be implemented as a macro, or other evil
+ *          subversions (oh, so much fun).
+ *
+ * ************************************************************************** **
+ */
+static void cache_free_entry( ubi_trNodePtr WarrenZevon )
+  {
+         ZERO_STRUCTP(WarrenZevon);
+         SAFE_FREE( WarrenZevon );
+  } /* cache_free_entry */
+
+/* ************************************************************************** **
+ * Initializes or clears the mangled cache.
+ *
+ *  Input:  none.
+ *  Output: none.
+ *
+ *  Notes:  There is a section below that is commented out.  It shows how
+ *          one might use lp_ calls to set the maximum memory and entry size
+ *          of the cache.  You might also want to remove the constants used
+ *          in ubi_cacheInit() and replace them with lp_ calls.  If so, then
+ *          the calls to ubi_cacheSetMax*() would be moved into the else
+ *          clause.  Another option would be to pass in the max_entries and
+ *          max_memory values as parameters.  crh 09-Apr-1998.
+ *
+ * ************************************************************************** **
+ */
+void reset_mangled_cache( void )
+  {
+  if( !mc_initialized )
+    {
+    (void)ubi_cacheInit( mangled_cache,
+                         cache_compare,
+                         cache_free_entry,
+                         MANGLED_CACHE_MAX_ENTRIES,
+                         MANGLED_CACHE_MAX_MEMORY );
+    mc_initialized = True;
+    }
+  else
+    {
+    (void)ubi_cacheClear( mangled_cache );
+    }
+
+  /*
+  (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
+  (void)ubi_cacheSetMaxMemory(  mangled_cache, lp_mangled_cache_memory() );
+  */
+  } /* reset_mangled_cache  */
+
+
+/* ************************************************************************** **
+ * Add a mangled name into the cache.
+ *
+ *  Notes:  If the mangled cache has not been initialized, then the
+ *          function will simply fail.  It could initialize the cache,
+ *          but that's not the way it was done before I changed the
+ *          cache mechanism, so I'm sticking with the old method.
+ *
+ *          If the extension of the raw name maps directly to the
+ *          extension of the mangled name, then we'll store both names
+ *          *without* extensions.  That way, we can provide consistent
+ *          reverse mangling for all names that match.  The test here is
+ *          a bit more careful than the one done in earlier versions of
+ *          mangle.c:
+ *
+ *            - the extension must exist on the raw name,
+ *            - it must be all lower case
+ *            - it must match the mangled extension (to prove that no
+ *              mangling occurred).
+ *
+ *  crh 07-Apr-1998
+ *
+ * ************************************************************************** **
+ */
+static void cache_mangled_name( char *mangled_name, char *raw_name )
+  {
+  ubi_cacheEntryPtr new_entry;
+  char             *s1;
+  char             *s2;
+  size_t               mangled_len;
+  size_t               raw_len;
+  size_t               i;
+
+  /* If the cache isn't initialized, give up. */
+  if( !mc_initialized )
+    return;
+
+  /* Init the string lengths. */
+  mangled_len = strlen( mangled_name );
+  raw_len     = strlen( raw_name );
+
+  /* See if the extensions are unmangled.  If so, store the entry
+   * without the extension, thus creating a "group" reverse map.
+   */
+  s1 = strrchr( mangled_name, '.' );
+  if( s1 && (s2 = strrchr( raw_name, '.' )) )
+    {
+    i = 1;
+    while( s1[i] && (tolower( s1[1] ) == s2[i]) )
+      i++;
+    if( !s1[i] && !s2[i] )
+      {
+      mangled_len -= i;
+      raw_len     -= i;
+      }
+    }
+
+  /* Allocate a new cache entry.  If the allocation fails, just return. */
+  i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
+  new_entry = malloc( i );
+  if( !new_entry )
+    return;
+
+  /* Fill the new cache entry, and add it to the cache. */
+  s1 = (char *)(new_entry + 1);
+  s2 = (char *)&(s1[mangled_len + 1]);
+  (void)StrnCpy( s1, mangled_name, mangled_len );
+  (void)StrnCpy( s2, raw_name,     raw_len );
+  ubi_cachePut( mangled_cache, i, new_entry, s1 );
+  } /* cache_mangled_name */
+
+/* ************************************************************************** **
+ * Check for a name on the mangled name stack
+ *
+ *  Input:  s - Input *and* output string buffer.
+ *
+ *  Output: True if the name was found in the cache, else False.
+ *
+ *  Notes:  If a reverse map is found, the function will overwrite the string
+ *          space indicated by the input pointer <s>.  This is frightening.
+ *          It should be rewritten to return NULL if the long name was not
+ *          found, and a pointer to the long name if it was found.
+ *
+ * ************************************************************************** **
+ */
 
-static void unmangle_test (char *name, char *ext)
+BOOL check_mangled_cache( char *s )
 {
-       smb_ucs2_t ucs2_name[2048];
-       smb_ucs2_t *retstr;
-       pstring unix_name;      
+  ubi_cacheEntryPtr FoundPtr;
+  char             *ext_start = NULL;
+  char             *found_name;
+  char             *saved_ext = NULL;
+
+  /* If the cache isn't initialized, give up. */
+  if( !mc_initialized )
+    return( False );
+
+  FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
+
+  /* If we didn't find the name *with* the extension, try without. */
+  if( !FoundPtr )
+  {
+    ext_start = strrchr( s, '.' );
+    if( ext_start )
+    {
+      if((saved_ext = strdup(ext_start)) == NULL)
+        return False;
+
+      *ext_start = '\0';
+      FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
+      /* 
+       * At this point s is the name without the
+       * extension. We re-add the extension if saved_ext
+       * is not null, before freeing saved_ext.
+       */
+    }
+  }
+
+  /* Okay, if we haven't found it we're done. */
+  if( !FoundPtr )
+  {
+    if(saved_ext)
+    {
+      /* Replace the saved_ext as it was truncated. */
+      (void)pstrcat( s, saved_ext );
+      SAFE_FREE(saved_ext);
+    }
+    return( False );
+  }
+
+  /* If we *did* find it, we need to copy it into the string buffer. */
+  found_name = (char *)(FoundPtr + 1);
+  found_name += (strlen( found_name ) + 1);
+
+  DEBUG( 3, ("Found %s on mangled stack ", s) );
+
+  (void)pstrcpy( s, found_name );
+  if( saved_ext )
+  {
+    /* Replace the saved_ext as it was truncated. */
+    (void)pstrcat( s, saved_ext );
+    SAFE_FREE(saved_ext);
+  }
+
+  DEBUG( 3, ("as %s\n", s) );
+
+  return( True );
+} /* check_mangled_cache */
+
+
+/* ************************************************************************** **
+ * Used only in do_fwd_mangled_map(), below.
+ * ************************************************************************** **
+ */
+static char *map_filename( char *s,         /* This is null terminated */
+                           char *pattern,   /* This isn't. */
+                           int len )        /* This is the length of pattern. */
+  {
+  static pstring matching_bit;  /* The bit of the string which matches */
+                                /* a * in pattern if indeed there is a * */
+  char *sp;                     /* Pointer into s. */
+  char *pp;                     /* Pointer into p. */
+  char *match_start;            /* Where the matching bit starts. */
+  pstring pat;
+
+  StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */
+  pstrcpy( matching_bit, "" );  /* Match but no star gets this. */
+  pp = pat;                     /* Initialize the pointers. */
+  sp = s;
+
+  if( strequal(s, ".") || strequal(s, ".."))
+    {
+    return NULL;                /* Do not map '.' and '..' */
+    }
+
+  if( (len == 1) && (*pattern == '*') )
+    {
+    return NULL;                /* Impossible, too ambiguous for */
+    }                           /* words! */
+
+  while( (*sp)                  /* Not the end of the string. */
+      && (*pp)                  /* Not the end of the pattern. */
+      && (*sp == *pp)           /* The two match. */
+      && (*pp != '*') )         /* No wildcard. */
+    {
+    sp++;                       /* Keep looking. */
+    pp++;
+    }
+
+  if( !*sp && !*pp )            /* End of pattern. */
+    return( matching_bit );     /* Simple match.  Return empty string. */
+
+  if( *pp == '*' )
+    {
+    pp++;                       /* Always interrested in the chacter */
+                                /* after the '*' */
+    if( !*pp )                  /* It is at the end of the pattern. */
+      {
+      StrnCpy( matching_bit, s, sp-s );
+      return( matching_bit );
+      }
+    else
+      {
+      /* The next character in pattern must match a character further */
+      /* along s than sp so look for that character. */
+      match_start = sp;
+      while( (*sp)              /* Not the end of s. */
+          && (*sp != *pp) )     /* Not the same  */
+        sp++;                   /* Keep looking. */
+      if( !*sp )                /* Got to the end without a match. */
+        {
+        return( NULL );
+        }                       /* Still hope for a match. */
+      else
+        {
+        /* Now sp should point to a matching character. */
+        StrnCpy(matching_bit, match_start, sp-match_start);
+        /* Back to needing a stright match again. */
+        while( (*sp)            /* Not the end of the string. */
+            && (*pp)            /* Not the end of the pattern. */
+            && (*sp == *pp) )   /* The two match. */
+          {
+          sp++;                 /* Keep looking. */
+          pp++;
+          }
+        if( !*sp && !*pp )      /* Both at end so it matched */
+          return( matching_bit );
+        else
+          return( NULL );
+        }
+      }
+    }
+  return( NULL );               /* No match. */
+  } /* map_filename */
+
+
+/* ************************************************************************** **
+ * MangledMap is a series of name pairs in () separated by spaces.
+ * If s matches the first of the pair then the name given is the
+ * second of the pair.  A * means any number of any character and if
+ * present in the second of the pair as well as the first the
+ * matching part of the first string takes the place of the * in the
+ * second.
+ *
+ * I wanted this so that we could have RCS files which can be used
+ * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
+ * converts the UNIX RCS file subdirectory to lowercase thus
+ * preventing mangling.
+ *
+ * (I think Andrew wrote the above, but I'm not sure. -- CRH)
+ *
+ * See 'mangled map' in smb.conf(5).
+ *
+ * ************************************************************************** **
+ */
+static void do_fwd_mangled_map(char *s, char *MangledMap)
+  {
+  char *start=MangledMap;       /* Use this to search for mappings. */
+  char *end;                    /* Used to find the end of strings. */
+  char *match_string;
+  pstring new_string;           /* Make up the result here. */
+  char *np;                     /* Points into new_string. */
+
+  DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) );
+  while( *start )
+    {
+    while( (*start) && (*start != '(') )
+      start++;
+    if( !*start )
+      continue;                 /* Always check for the end. */
+    start++;                    /* Skip the ( */
+    end = start;                /* Search for the ' ' or a ')' */
+    DEBUG( 5, ("Start of first in pair '%s'\n", start) );
+    while( (*end) && !((*end == ' ') || (*end == ')')) )
+      end++;
+    if( !*end )
+      {
+      start = end;
+      continue;                 /* Always check for the end. */
+      }
+    DEBUG( 5, ("End of first in pair '%s'\n", end) );
+    if( (match_string = map_filename( s, start, end-start )) )
+      {
+      DEBUG( 5, ("Found a match\n") );
+      /* Found a match. */
+      start = end + 1;          /* Point to start of what it is to become. */
+      DEBUG( 5, ("Start of second in pair '%s'\n", start) );
+      end = start;
+      np = new_string;
+      while( (*end)             /* Not the end of string. */
+          && (*end != ')')      /* Not the end of the pattern. */
+          && (*end != '*') )    /* Not a wildcard. */
+        *np++ = *end++;
+      if( !*end )
+        {
+        start = end;
+        continue;               /* Always check for the end. */
+        }
+      if( *end == '*' )
+        {
+        pstrcpy( np, match_string );
+        np += strlen( match_string );
+        end++;                  /* Skip the '*' */
+        while( (*end)             /* Not the end of string. */
+            && (*end != ')')      /* Not the end of the pattern. */
+            && (*end != '*') )    /* Not a wildcard. */
+          *np++ = *end++;
+        }
+      if( !*end )
+        {
+        start = end;
+        continue;               /* Always check for the end. */
+        }
+      *np++ = '\0';             /* NULL terminate it. */
+      DEBUG(5,("End of second in pair '%s'\n", end));
+      pstrcpy( s, new_string );  /* Substitute with the new name. */
+      DEBUG( 5, ("s is now '%s'\n", s) );
+      }
+    start = end;              /* Skip a bit which cannot be wanted anymore. */
+    start++;
+    }
+  } /* do_fwd_mangled_map */
+
+/*****************************************************************************
+ * do the actual mangling to 8.3 format
+ * the buffer must be able to hold 13 characters (including the null)
+ *****************************************************************************
+ */
+void mangle_name_83( char *s)
+  {
+  int csum;
+  char *p;
+  char extension[4];
+  char base[9];
+  int baselen = 0;
+  int extlen = 0;
+
+  extension[0] = 0;
+  base[0] = 0;
+
+  p = strrchr(s,'.');  
+  if( p && (strlen(p+1) < (size_t)4) )
+    {
+    BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
+
+    if( all_normal && p[1] != 0 )
+      {
+      *p = 0;
+      csum = str_checksum( s );
+      *p = '.';
+      }
+    else
+      csum = str_checksum(s);
+    }
+  else
+    csum = str_checksum(s);
+
+  strupper( s );
+
+  DEBUG( 5, ("Mangling name %s to ",s) );
+
+  if( p )
+  {
+         if( p == s )
+                 safe_strcpy( extension, "___", 3 );
+         else
+         {
+                 *p++ = 0;
+                 while( *p && extlen < 3 )
+                 {
+                         if ( *p != '.') {
+                                 extension[extlen++] = p[0];
+                         }
+                         p++;
+                 }
+                 extension[extlen] = 0;
+      }
+  }
+  
+  p = s;
+
+  while( *p && baselen < 5 )
+  {
+         if (*p != '.') {
+                 base[baselen++] = p[0];
+         }
+         p++;
+  }
+  base[baselen] = 0;
+  
+  csum = csum % (MANGLE_BASE*MANGLE_BASE);
+  
+  (void)slprintf(s, 12, "%s%c%c%c",
+                 base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
+  
+  if( *extension )
+  {
+         (void)pstrcat( s, "." );
+         (void)pstrcat( s, extension );
+  }
+  
+  DEBUG( 5, ( "%s\n", s ) );
+
+  } /* mangle_name_83 */
+
+/*****************************************************************************
+ * Convert a filename to DOS format.  Return True if successful.
+ *
+ *  Input:  OutName - Source *and* destination buffer. 
+ *
+ *                    NOTE that OutName must point to a memory space that
+ *                    is at least 13 bytes in size!
+ *
+ *          need83  - If False, name mangling will be skipped unless the
+ *                    name contains illegal characters.  Mapping will still
+ *                    be done, if appropriate.  This is probably used to
+ *                    signal that a client does not require name mangling,
+ *                    thus skipping the name mangling even on shares which
+ *                    have name-mangling turned on.
+ *          cache83 - If False, the mangled name cache will not be updated.
+ *                    This is usually used to prevent that we overwrite
+ *                    a conflicting cache entry prematurely, i.e. before
+ *                    we know whether the client is really interested in the
+ *                    current name.  (See PR#13758).  UKD.
+ *          snum    - Share number.  This identifies the share in which the
+ *                    name exists.
+ *
+ *  Output: Returns False only if the name wanted mangling but the share does
+ *          not have name mangling turned on.
+ *
+ * ****************************************************************************
+ */
+BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
+{
+       char *map;
+       smb_ucs2_t *OutName_ucs2;
+       DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
+                need83 ? "True" : "False", cache83 ? "True" : "False", snum));
+       
+       if (push_ucs2_allocate((void **)&OutName_ucs2, OutName) < 0) {
+               DEBUG(0, ("push_ucs2_allocate failed!\n"));
+               return False;
+       }
 
-       push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
-       if (ext)
-       {
-               strncat_wa(ucs2_name, ".", 1);
-               strncat_wa(ucs2_name, ext, strlen(ext) + 1);
+       /* apply any name mappings */
+       map = lp_mangled_map(snum);
+
+       if (map && *map) {
+               do_fwd_mangled_map( OutName, map );
        }
-       retstr = unmangle(ucs2_name);
-       if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
-       else unix_name[0] = 0;
-       if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
-       else printf ("[%s] ---> [%s]\n", name, unix_name);
-       SAFE_FREE(retstr);
-}
 
-static void mangle_test (char *name, char *ext)
-{
-       smb_ucs2_t ucs2_name[2048];
-       smb_ucs2_t *retstr;
-       pstring unix_name;      
+       /* check if it's already in 8.3 format */
+       if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2))) {
+               char *tmp = NULL; 
 
-       push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
-       if (ext)
-       {
-               strncat_wa(ucs2_name, ".", 1);
-               strncat_wa(ucs2_name, ext, strlen(ext) + 1);
+               if (!lp_manglednames(snum)) {
+                       return(False);
+               }
+
+               /* mangle it into 8.3 */
+               if (cache83)
+                       tmp = strdup(OutName);
+
+               mangle_name_83(OutName);
+
+               if(tmp != NULL) {
+                       cache_mangled_name(OutName, tmp);
+                       SAFE_FREE(tmp);
+               }
        }
-       retstr = mangle(ucs2_name);
-       if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
-       else unix_name[0] = 0;
-       if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
-       else printf ("[%s] ---> [%s]\n", name, unix_name);
-       SAFE_FREE(retstr);
-}
 
-void mangle_test_code(void)
-{
-       init_mangle_tdb();
-
-       /* unmangle every */
-       printf("Unmangle test 1:\n");
-
-       unmangle_test (LONG, NULL);
-       unmangle_test (LONG, EXT1);
-       unmangle_test (LONG, EXT2);
-       unmangle_test (LONG, EXT3);
-       unmangle_test (LONG, EXTFAIL);
-       unmangle_test (LONG, EXTNULL);
-
-       unmangle_test (LONGM, NULL);
-       unmangle_test (LONGM, EXT1);
-       unmangle_test (LONGM, EXT2);
-       unmangle_test (LONGM, EXT3);
-       unmangle_test (LONGM, EXTFAIL);
-       unmangle_test (LONGM, EXTNULL);
-
-       unmangle_test (SHORT, NULL);
-       unmangle_test (SHORT, EXT1);
-       unmangle_test (SHORT, EXT2);
-       unmangle_test (SHORT, EXT3);
-       unmangle_test (SHORT, EXTFAIL);
-       unmangle_test (SHORT, EXTNULL);
-
-       unmangle_test (SHORTM, NULL);
-       unmangle_test (SHORTM, EXT1);
-       unmangle_test (SHORTM, EXT2);
-       unmangle_test (SHORTM, EXT3);
-       unmangle_test (SHORTM, EXTFAIL);
-       unmangle_test (SHORTM, EXTNULL);
-
-       /* mangle every */
-       printf("Mangle test\n");
-
-       mangle_test (LONG, NULL);
-       mangle_test (LONG, EXT1);
-       mangle_test (LONG, EXT2);
-       mangle_test (LONG, EXT3);
-       mangle_test (LONG, EXTFAIL);
-       mangle_test (LONG, EXTNULL);
-
-       mangle_test (LONGM, NULL);
-       mangle_test (LONGM, EXT1);
-       mangle_test (LONGM, EXT2);
-       mangle_test (LONGM, EXT3);
-       mangle_test (LONGM, EXTFAIL);
-       mangle_test (LONGM, EXTNULL);
-
-       mangle_test (SHORT, NULL);
-       mangle_test (SHORT, EXT1);
-       mangle_test (SHORT, EXT2);
-       mangle_test (SHORT, EXT3);
-       mangle_test (SHORT, EXTFAIL);
-       mangle_test (SHORT, EXTNULL);
-
-       mangle_test (SHORTM, NULL);
-       mangle_test (SHORTM, EXT1);
-       mangle_test (SHORTM, EXT2);
-       mangle_test (SHORTM, EXT3);
-       mangle_test (SHORTM, EXTFAIL);
-       mangle_test (SHORTM, EXTNULL);
-
-       /* unmangle again every */
-       printf("Unmangle test 2:\n");
-
-       unmangle_test (LONG, NULL);
-       unmangle_test (LONG, EXT1);
-       unmangle_test (LONG, EXT2);
-       unmangle_test (LONG, EXT3);
-       unmangle_test (LONG, EXTFAIL);
-       unmangle_test (LONG, EXTNULL);
-
-       unmangle_test (LONGM, NULL);
-       unmangle_test (LONGM, EXT1);
-       unmangle_test (LONGM, EXT2);
-       unmangle_test (LONGM, EXT3);
-       unmangle_test (LONGM, EXTFAIL);
-       unmangle_test (LONGM, EXTNULL);
-
-       unmangle_test (SHORT, NULL);
-       unmangle_test (SHORT, EXT1);
-       unmangle_test (SHORT, EXT2);
-       unmangle_test (SHORT, EXT3);
-       unmangle_test (SHORT, EXTFAIL);
-       unmangle_test (SHORT, EXTNULL);
-
-       unmangle_test (SHORTM, NULL);
-       unmangle_test (SHORTM, EXT1);
-       unmangle_test (SHORTM, EXT2);
-       unmangle_test (SHORTM, EXT3);
-       unmangle_test (SHORTM, EXTFAIL);
-       unmangle_test (SHORTM, EXTNULL);
-}
+       DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
+       SAFE_FREE(OutName_ucs2);
+       return(True);
+} /* name_map_mangle */
 
-#endif /* TEST_MANGLE_CODE */
index af582f1a41c917be0a7fdddfe95175c430b08596..421f8862838354efe0585fc0a40f311647f2f60d 100644 (file)
@@ -3021,10 +3021,10 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-#if 0
+#if 1
        if (!rc && is_mangled(mask))
                check_mangled_cache( mask );
-#endif
+#else
        if (!rc)
        {
                char *unmangled;
@@ -3035,6 +3035,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO
                        
                SAFE_FREE(unmangled);
        }
+#endif
 
        has_wild = ms_has_wild(mask);
 
@@ -3437,10 +3438,10 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
    * Tine Smukavec <valentin.smukavec@hermes.si>.
    */
 
-#if 0
+#if 1
        if (!rc && is_mangled(mask))
                check_mangled_cache( mask );
-#endif
+#else
        if (!rc)
        {
                char *unmangled;
@@ -3451,7 +3452,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                        
                SAFE_FREE(unmangled);
        }
-
+#endif
 
   has_wild = ms_has_wild(mask);
 
index a9f3989735567e4e00f4dbd9d84d2c0a04eb87c8..e3912ba939527ea06b54ed202d5773abba945782 100644 (file)
@@ -888,10 +888,6 @@ static void usage(char *pname)
        if (!init_oplocks())
                exit(1);
        
-       /* Setup mangle */
-       if (!init_mangle_tdb())
-               exit(1);
-
        /* Setup change notify */
        if (!init_change_notify())
                exit(1);