[PATCH] Updated Name mangling patch for HEAD

Andrew Bartlett abartlet at pcug.org.au
Tue Mar 26 02:55:02 GMT 2002


This patch works for filenames with spaces - the previous version would
not mangle these for the long filename, causing much client confusion.

I still need to finish the conversion of the code to unicode.

Andrew Bartlett
-- 
Andrew Bartlett                                 abartlet at pcug.org.au
Manager, Authentication Subsystems, Samba Team  abartlet at samba.org
Student Network Administrator, Hawker College   abartlet at hawkerc.net
http://samba.org     http://build.samba.org     http://hawkerc.net
-------------- next part --------------
Index: source/smbd/filename.c
===================================================================
RCS file: /data/cvs/samba/source/smbd/filename.c,v
retrieving revision 1.46
diff -u -r1.46 filename.c
--- source/smbd/filename.c	2002/01/30 06:08:38	1.46
+++ source/smbd/filename.c	2002/03/26 10:32:36
@@ -75,6 +75,17 @@
 ****************************************************************************/
 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 @@
 		SAFE_FREE(tmpname);
 	}
 	return ret;
+#endif
+	
 }
 
 
@@ -116,7 +129,7 @@
 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: source/smbd/mangle.c
===================================================================
RCS file: /data/cvs/samba/source/smbd/mangle.c,v
retrieving revision 1.66
diff -u -r1.66 mangle.c
--- source/smbd/mangle.c	2002/03/14 22:52:19	1.66
+++ source/smbd/mangle.c	2002/03/26 10:32:38
@@ -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
    
@@ -19,9 +20,31 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/****************************************************************************
-  Rewritten from scrach in 2001 by Simo Sorce <idra at 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"
 
@@ -33,36 +56,88 @@
 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 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
 
-static TDB_CONTEXT	*mangle_tdb;
 
-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 */
+/* -------------------------------------------------------------------------- **
+ * External Variables...
+ */
 
-	/* 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;
-	}
+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. */
 
-	return True;
-}
+/* -------------------------------------------------------------------- */
 
 /* trasform a unicode string into a dos charset string */
 static int ucs2_to_dos(char *dest, const smb_ucs2_t *src, int dest_len)
@@ -81,6 +156,24 @@
 	return ret;
 }
 
+NTSTATUS has_valid_chars(const smb_ucs2_t *s)
+{
+	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 NT_STATUS_OK;
+}
+
 /* trasform in a string that contain only valid chars for win filenames,
  not including a '.' */
 static void strvalid(smb_ucs2_t *src)
@@ -128,524 +221,19 @@
 	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)
+static NTSTATUS is_valid_name(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)
-{
 	smb_ucs2_t *str, *p;
 	NTSTATUS ret = NT_STATUS_OK;
 
@@ -702,297 +290,705 @@
 	SAFE_FREE(str);
 	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)
+static NTSTATUS is_8_3_w(const smb_ucs2_t *fname)
 {
-	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)
-{
-	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++;
+
+	DEBUG(10,("is_8_3: testing [%s]\n", f));
 
-	if (!s || !*s) return;
+	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;	
-
-	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);
+  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;
+  int skip;
+
+  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;
 	}
-	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;	
+	/* apply any name mappings */
+	map = lp_mangled_map(snum);
 
-	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 (map && *map) {
+		do_fwd_mangled_map( OutName, map );
 	}
-	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();
+	/* check if it's already in 8.3 format */
+	if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2))) {
+		char *tmp = NULL; 
 
-	/* unmangle every */
-	printf("Unmangle test 1:\n");
+		if (!lp_manglednames(snum)) {
+			return(False);
+		}
 
-	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);
-}
+		/* 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);
+		}
+	}
+
+	DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
+	SAFE_FREE(OutName_ucs2);
+	return(True);
+} /* name_map_mangle */
 
-#endif /* TEST_MANGLE_CODE */
Index: source/smbd/reply.c
===================================================================
RCS file: /data/cvs/samba/source/smbd/reply.c,v
retrieving revision 1.376
diff -u -r1.376 reply.c
--- source/smbd/reply.c	2002/03/23 02:57:43	1.376
+++ source/smbd/reply.c	2002/03/26 10:32:41
@@ -3054,10 +3054,10 @@
 	 * Tine Smukavec <valentin.smukavec at hermes.si>.
 	 */
 
-#if 0
+#if 1
 	if (!rc && is_mangled(mask))
 		check_mangled_cache( mask );
-#endif
+#else
 	if (!rc)
 	{
 		char *unmangled;
@@ -3068,6 +3068,7 @@
 			
 		SAFE_FREE(unmangled);
 	}
+#endif
 
 	has_wild = ms_has_wild(mask);
 
@@ -3470,10 +3471,10 @@
    * Tine Smukavec <valentin.smukavec at hermes.si>.
    */
 
-#if 0
+#if 1
 	if (!rc && is_mangled(mask))
 		check_mangled_cache( mask );
-#endif
+#else
 	if (!rc)
 	{
 		char *unmangled;
@@ -3484,7 +3485,7 @@
 			
 		SAFE_FREE(unmangled);
 	}
-
+#endif
 
   has_wild = ms_has_wild(mask);
 
Index: source/smbd/server.c
===================================================================
RCS file: /data/cvs/samba/source/smbd/server.c,v
retrieving revision 1.369
diff -u -r1.369 server.c
--- source/smbd/server.c	2002/03/14 02:15:08	1.369
+++ source/smbd/server.c	2002/03/26 10:32:42
@@ -882,10 +882,6 @@
 	if (!init_oplocks())
 		exit(1);
 	
-	/* Setup mangle */
-	if (!init_mangle_tdb())
-		exit(1);
-
 	/* Setup change notify */
 	if (!init_change_notify())
 		exit(1);


More information about the samba-technical mailing list