Removed 'extern int DEBUGLEVEL' as it is now in the smb.h header.
[kai/samba.git] / source3 / smbd / mangle.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Name mangling
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /* -------------------------------------------------------------------------- **
23  * Notable problems...
24  *
25  *  March/April 1998  CRH
26  *  - Many of the functions in this module overwrite string buffers passed to
27  *    them.  This causes a variety of problems and is, generally speaking,
28  *    dangerous and scarry.  See the kludge notes in name_map_mangle()
29  *    below.
30  *  - It seems that something is calling name_map_mangle() twice.  The
31  *    first call is probably some sort of test.  Names which contain
32  *    illegal characters are being doubly mangled.  I'm not sure, but
33  *    I'm guessing the problem is in server.c.
34  *
35  * -------------------------------------------------------------------------- **
36  */
37
38 /* -------------------------------------------------------------------------- **
39  * History...
40  *
41  *  March/April 1998  CRH
42  *  Updated a bit.  Rewrote is_mangled() to be a bit more selective.
43  *  Rewrote the mangled name cache.  Added comments here and there.
44  *  &c.
45  * -------------------------------------------------------------------------- **
46  */
47
48 #include "includes.h"
49
50
51 /* -------------------------------------------------------------------------- **
52  * External Variables...
53  */
54
55 extern int case_default;    /* Are conforming 8.3 names all upper or lower?   */
56 extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
57
58 /* -------------------------------------------------------------------------- **
59  * Other stuff...
60  *
61  * magic_char     - This is the magic char used for mangling.  It's
62  *                  global.  There is a call to lp_magicchar() in server.c
63  *                  that is used to override the initial value.
64  *
65  * MANGLE_BASE    - This is the number of characters we use for name mangling.
66  *
67  * basechars      - The set characters used for name mangling.  This
68  *                  is static (scope is this file only).
69  *
70  * mangle()       - Macro used to select a character from basechars (i.e.,
71  *                  mangle(n) will return the nth digit, modulo MANGLE_BASE).
72  *
73  * chartest       - array 0..255.  The index range is the set of all possible
74  *                  values of a byte.  For each byte value, the content is a
75  *                  two nibble pair.  See BASECHAR_MASK and ILLEGAL_MASK,
76  *                  below.
77  *
78  * ct_initialized - False until the chartest array has been initialized via
79  *                  a call to init_chartest().
80  *
81  * BASECHAR_MASK  - Masks the upper nibble of a one-byte value.
82  *
83  * ILLEGAL_MASK   - Masks the lower nibble of a one-byte value.
84  *
85  * isbasecahr()   - Given a character, check the chartest array to see
86  *                  if that character is in the basechars set.  This is
87  *                  faster than using strchr_m().
88  *
89  * isillegal()    - Given a character, check the chartest array to see
90  *                  if that character is in the illegal characters set.
91  *                  This is faster than using strchr_m().
92  *
93  * mangled_cache  - Cache header used for storing mangled -> original
94  *                  reverse maps.
95  *
96  * mc_initialized - False until the mangled_cache structure has been
97  *                  initialized via a call to reset_mangled_cache().
98  *
99  * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
100  *                  cache.  A value of 0 indicates "infinite".
101  *
102  * MANGLED_CACHE_MAX_MEMORY  - Default maximum amount of memory for the
103  *                  cache.  When the cache was kept as an array of 256
104  *                  byte strings, the default cache size was 50 entries.
105  *                  This required a fixed 12.5Kbytes of memory.  The
106  *                  mangled stack parameter is no longer used (though
107  *                  this might change).  We're now using a fixed 16Kbyte
108  *                  maximum cache size.  This will probably be much more
109  *                  than 50 entries.
110  */
111
112 char magic_char = '~';
113
114 static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
115 #define MANGLE_BASE       ( (sizeof(basechars)/sizeof(char)) - 1 )
116
117 static unsigned char chartest[256]  = { 0 };
118 static BOOL          ct_initialized = False;
119
120 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
121 #define BASECHAR_MASK 0xf0
122 #define ILLEGAL_MASK  0x0f
123 #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
124 #define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
125
126 static ubi_cacheRoot mangled_cache[1] = {{ { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 }};
127 static BOOL          mc_initialized   = False;
128 #define MANGLED_CACHE_MAX_ENTRIES 0
129 #define MANGLED_CACHE_MAX_MEMORY  16384
130
131
132 /* -------------------------------------------------------------------------- **
133  * Functions...
134  */
135
136 /* ************************************************************************** **
137  * Initialize the static character test array.
138  *
139  *  Input:  none
140  *
141  *  Output: none
142  *
143  *  Notes:  This function changes (loads) the contents of the <chartest>
144  *          array.  The scope of <chartest> is this file.
145  *
146  * ************************************************************************** **
147  */
148 static void init_chartest( void )
149   {
150   char          *illegalchars = "*\\/?<>|\":";
151   unsigned char *s;
152   
153   memset( (char *)chartest, '\0', 256 );
154
155   for( s = (unsigned char *)illegalchars; *s; s++ )
156     chartest[*s] = ILLEGAL_MASK;
157
158   for( s = (unsigned char *)basechars; *s; s++ )
159     chartest[*s] |= BASECHAR_MASK;
160
161   ct_initialized = True;
162   } /* init_chartest */
163
164 /* ************************************************************************** **
165  * Return True if a name is a special msdos reserved name.
166  *
167  *  Input:  fname - String containing the name to be tested.
168  *
169  *  Output: True, if the name matches one of the list of reserved names.
170  *
171  *  Notes:  This is a static function called by is_8_3(), below.
172  *
173  * ************************************************************************** **
174  */
175 static BOOL is_reserved_msdos( char *fname )
176   {
177   char upperFname[13];
178   char *p;
179
180   StrnCpy (upperFname, fname, 12);
181
182   /* lpt1.txt and con.txt etc are also illegal */
183   p = strchr_m(upperFname,'.');
184   if( p )
185     *p = '\0';
186
187   strupper( upperFname );
188   p = upperFname + 1;
189   switch( upperFname[0] )
190     {
191     case 'A':
192       if( 0 == strcmp( p, "UX" ) )
193         return( True );
194       break;
195     case 'C':
196       if( (0 == strcmp( p, "LOCK$" ))
197        || (0 == strcmp( p, "ON" ))
198        || (0 == strcmp( p, "OM1" ))
199        || (0 == strcmp( p, "OM2" ))
200        || (0 == strcmp( p, "OM3" ))
201        || (0 == strcmp( p, "OM4" ))
202         )
203         return( True );
204       break;
205     case 'L':
206       if( (0 == strcmp( p, "PT1" ))
207        || (0 == strcmp( p, "PT2" ))
208        || (0 == strcmp( p, "PT3" ))
209         )
210         return( True );
211       break;
212     case 'N':
213       if( 0 == strcmp( p, "UL" ) )
214         return( True );
215       break;
216     case 'P':
217       if( 0 == strcmp( p, "RN" ) )
218         return( True );
219       break;
220     }
221
222   return( False );
223   } /* is_reserved_msdos */
224
225 /* ************************************************************************** **
226  * Determine whether or not a given name contains illegal characters, even
227  * long names.
228  *
229  *  Input:  name  - The name to be tested.
230  *
231  *  Output: True if an illegal character was found in <name>, else False.
232  *
233  *  Notes:  This is used to test a name on the host system, long or short,
234  *          for characters that would be illegal on most client systems,
235  *          particularly DOS and Windows systems.  Unix and AmigaOS, for
236  *          example, allow a filenames which contain such oddities as
237  *          quotes (").  If a name is found which does contain an illegal
238  *          character, it is mangled even if it conforms to the 8.3
239  *          format.
240  *
241  * ************************************************************************** **
242  */
243 static BOOL is_illegal_name( char *name )
244   {
245   unsigned char *s;
246
247   if( !name )
248     return( True );
249
250   if( !ct_initialized )
251     init_chartest();
252
253   s = (unsigned char *)name;
254   while( *s )
255     {
256       if( *s>0x7F && isillegal( *s ) )
257         return( True );
258       else
259         s++;
260     }
261
262   return( False );
263   } /* is_illegal_name */
264
265 /* ************************************************************************** **
266  * Return True if the name *could be* a mangled name.
267  *
268  *  Input:  s - A path name - in UNIX pathname format.
269  *
270  *  Output: True if the name matches the pattern described below in the
271  *          notes, else False.
272  *
273  *  Notes:  The input name is *not* tested for 8.3 compliance.  This must be
274  *          done separately.  This function returns true if the name contains
275  *          a magic character followed by excactly two characters from the
276  *          basechars list (above), which in turn are followed either by the
277  *          nul (end of string) byte or a dot (extension) or by a '/' (end of
278  *          a directory name).
279  *
280  * ************************************************************************** **
281  */
282 BOOL is_mangled( char *s )
283   {
284   char *magic;
285
286   if( !ct_initialized )
287     init_chartest();
288
289   magic = strchr_m( s, magic_char );
290   while( magic && magic[1] && magic[2] )          /* 3 chars, 1st is magic. */
291     {
292     if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
293      && isbasechar( toupper(magic[1]) )           /* is 2nd char basechar?  */
294      && isbasechar( toupper(magic[2]) ) )         /* is 3rd char basechar?  */
295       return( True );                           /* If all above, then true, */
296     magic = strchr_m( magic+1, magic_char );      /*    else seek next magic. */
297     }
298   return( False );
299   } /* is_mangled */
300
301 /* ************************************************************************** **
302  * Return True if the name is a valid DOS name in 8.3 DOS format.
303  *
304  *  Input:  fname       - File name to be checked.
305  *          check_case  - If True, and if case_mangle is True, then the
306  *                        name will be checked to see if all characters
307  *                        are the correct case.  See case_mangle and
308  *                        case_default above.
309  *
310  *  Output: True if the name is a valid DOS name, else FALSE.
311  *
312  * ************************************************************************** **
313  */
314 BOOL is_8_3( char *fname, BOOL check_case )
315   {
316   int   len;
317   int   l;
318   char *p;
319   char *dot_pos;
320   char *slash_pos = strrchr_m( fname, '/' );
321
322   /* If there is a directory path, skip it. */
323   if( slash_pos )
324     fname = slash_pos + 1;
325   len = strlen( fname );
326
327   DEBUG( 5, ( "Checking %s for 8.3\n", fname ) );
328
329   /* Can't be 0 chars or longer than 12 chars */
330   if( (len == 0) || (len > 12) )
331     return( False );
332
333   /* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
334   if( is_reserved_msdos( fname ) )
335     return( False );
336
337   /* Check that all characters are the correct case, if asked to do so. */
338   if( check_case && case_mangle )
339     {
340     switch( case_default )
341       {
342       case CASE_LOWER:
343         if( strhasupper( fname ) )
344           return(False);
345         break;
346       case CASE_UPPER:
347         if( strhaslower( fname ) )
348           return(False);
349         break;
350       }
351     }
352
353   /* Can't contain invalid dos chars */
354   /* Windows use the ANSI charset.
355      But filenames are translated in the PC charset.
356      This Translation may be more or less relaxed depending
357      the Windows application. */
358
359   /* %%% A nice improvment to name mangling would be to translate
360      filename to ANSI charset on the smb server host */
361
362   p       = fname;
363   dot_pos = NULL;
364   while( *p )
365     {
366       if( *p == '.' && !dot_pos )
367         dot_pos = (char *)p;
368       /*else
369         if( !isdoschar( *p ) )
370           return( False );*/
371       p++;
372     }
373
374   /* no dot and less than 9 means OK */
375   if( !dot_pos )
376     return( len <= 8 );
377         
378   l = PTR_DIFF( dot_pos, fname );
379
380   /* base must be at least 1 char except special cases . and .. */
381   if( l == 0 )
382     return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
383
384   /* base can't be greater than 8 */
385   if( l > 8 )
386     return( False );
387
388   /* see smb.conf(5) for a description of the 'strip dot' parameter. */
389   if( lp_strip_dot()
390    && len - l == 1
391    && !strchr_m( dot_pos + 1, '.' ) )
392     {
393     *dot_pos = 0;
394     return( True );
395     }
396
397   /* extension must be between 1 and 3 */
398   if( (len - l < 2 ) || (len - l > 4) )
399     return( False );
400
401   /* extensions may not have a dot */
402   if( strchr_m( dot_pos+1, '.' ) )
403     return( False );
404
405   /* must be in 8.3 format */
406   return( True );
407   } /* is_8_3 */
408
409
410 /* ************************************************************************** **
411  * Compare two cache keys and return a value indicating their ordinal
412  * relationship.
413  *
414  *  Input:  ItemPtr - Pointer to a comparison key.  In this case, this will
415  *                    be a mangled name string.
416  *          NodePtr - Pointer to a node in the cache.  The node structure
417  *                    will be followed in memory by a mangled name string.
418  *
419  *  Output: A signed integer, as follows:
420  *            (x < 0)  <==> Key1 less than Key2
421  *            (x == 0) <==> Key1 equals Key2
422  *            (x > 0)  <==> Key1 greater than Key2
423  *
424  *  Notes:  This is a ubiqx-style comparison routine.  See ubi_BinTree for
425  *          more info.
426  *
427  * ************************************************************************** **
428  */
429 static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
430   {
431   char *Key1 = (char *)ItemPtr;
432   char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
433
434   return( StrCaseCmp( Key1, Key2 ) );
435   } /* cache_compare */
436
437 /* ************************************************************************** **
438  * Free a cache entry.
439  *
440  *  Input:  WarrenZevon - Pointer to the entry that is to be returned to
441  *                        Nirvana.
442  *  Output: none.
443  *
444  *  Notes:  This function gets around the possibility that the standard
445  *          free() function may be implemented as a macro, or other evil
446  *          subversions (oh, so much fun).
447  *
448  * ************************************************************************** **
449  */
450 static void cache_free_entry( ubi_trNodePtr WarrenZevon )
451   {
452           ZERO_STRUCTP(WarrenZevon);
453           SAFE_FREE( WarrenZevon );
454   } /* cache_free_entry */
455
456 /* ************************************************************************** **
457  * Initializes or clears the mangled cache.
458  *
459  *  Input:  none.
460  *  Output: none.
461  *
462  *  Notes:  There is a section below that is commented out.  It shows how
463  *          one might use lp_ calls to set the maximum memory and entry size
464  *          of the cache.  You might also want to remove the constants used
465  *          in ubi_cacheInit() and replace them with lp_ calls.  If so, then
466  *          the calls to ubi_cacheSetMax*() would be moved into the else
467  *          clause.  Another option would be to pass in the max_entries and
468  *          max_memory values as parameters.  crh 09-Apr-1998.
469  *
470  * ************************************************************************** **
471  */
472 void reset_mangled_cache( void )
473   {
474   if( !mc_initialized )
475     {
476     (void)ubi_cacheInit( mangled_cache,
477                          cache_compare,
478                          cache_free_entry,
479                          MANGLED_CACHE_MAX_ENTRIES,
480                          MANGLED_CACHE_MAX_MEMORY );
481     mc_initialized = True;
482     }
483   else
484     {
485     (void)ubi_cacheClear( mangled_cache );
486     }
487
488   /*
489   (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
490   (void)ubi_cacheSetMaxMemory(  mangled_cache, lp_mangled_cache_memory() );
491   */
492   } /* reset_mangled_cache  */
493
494
495 /* ************************************************************************** **
496  * Add a mangled name into the cache.
497  *
498  *  Notes:  If the mangled cache has not been initialized, then the
499  *          function will simply fail.  It could initialize the cache,
500  *          but that's not the way it was done before I changed the
501  *          cache mechanism, so I'm sticking with the old method.
502  *
503  *          If the extension of the raw name maps directly to the
504  *          extension of the mangled name, then we'll store both names
505  *          *without* extensions.  That way, we can provide consistent
506  *          reverse mangling for all names that match.  The test here is
507  *          a bit more careful than the one done in earlier versions of
508  *          mangle.c:
509  *
510  *            - the extension must exist on the raw name,
511  *            - it must be all lower case
512  *            - it must match the mangled extension (to prove that no
513  *              mangling occurred).
514  *
515  *  crh 07-Apr-1998
516  *
517  * ************************************************************************** **
518  */
519 static void cache_mangled_name( char *mangled_name, char *raw_name )
520   {
521   ubi_cacheEntryPtr new_entry;
522   char             *s1;
523   char             *s2;
524   size_t               mangled_len;
525   size_t               raw_len;
526   size_t               i;
527
528   /* If the cache isn't initialized, give up. */
529   if( !mc_initialized )
530     return;
531
532   /* Init the string lengths. */
533   mangled_len = strlen( mangled_name );
534   raw_len     = strlen( raw_name );
535
536   /* See if the extensions are unmangled.  If so, store the entry
537    * without the extension, thus creating a "group" reverse map.
538    */
539   s1 = strrchr_m( mangled_name, '.' );
540   if( s1 && (s2 = strrchr_m( raw_name, '.' )) )
541     {
542     i = 1;
543     while( s1[i] && (tolower( s1[1] ) == s2[i]) )
544       i++;
545     if( !s1[i] && !s2[i] )
546       {
547       mangled_len -= i;
548       raw_len     -= i;
549       }
550     }
551
552   /* Allocate a new cache entry.  If the allocation fails, just return. */
553   i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
554   new_entry = malloc( i );
555   if( !new_entry )
556     return;
557
558   /* Fill the new cache entry, and add it to the cache. */
559   s1 = (char *)(new_entry + 1);
560   s2 = (char *)&(s1[mangled_len + 1]);
561   (void)StrnCpy( s1, mangled_name, mangled_len );
562   (void)StrnCpy( s2, raw_name,     raw_len );
563   ubi_cachePut( mangled_cache, i, new_entry, s1 );
564   } /* cache_mangled_name */
565
566 /* ************************************************************************** **
567  * Check for a name on the mangled name stack
568  *
569  *  Input:  s - Input *and* output string buffer.
570  *
571  *  Output: True if the name was found in the cache, else False.
572  *
573  *  Notes:  If a reverse map is found, the function will overwrite the string
574  *          space indicated by the input pointer <s>.  This is frightening.
575  *          It should be rewritten to return NULL if the long name was not
576  *          found, and a pointer to the long name if it was found.
577  *
578  * ************************************************************************** **
579  */
580
581 BOOL check_mangled_cache( char *s )
582 {
583   ubi_cacheEntryPtr FoundPtr;
584   char             *ext_start = NULL;
585   char             *found_name;
586   char             *saved_ext = NULL;
587
588   /* If the cache isn't initialized, give up. */
589   if( !mc_initialized )
590     return( False );
591
592   FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
593
594   /* If we didn't find the name *with* the extension, try without. */
595   if( !FoundPtr )
596   {
597     ext_start = strrchr_m( s, '.' );
598     if( ext_start )
599     {
600       if((saved_ext = strdup(ext_start)) == NULL)
601         return False;
602
603       *ext_start = '\0';
604       FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
605       /* 
606        * At this point s is the name without the
607        * extension. We re-add the extension if saved_ext
608        * is not null, before freeing saved_ext.
609        */
610     }
611   }
612
613   /* Okay, if we haven't found it we're done. */
614   if( !FoundPtr )
615   {
616     if(saved_ext)
617     {
618       /* Replace the saved_ext as it was truncated. */
619       (void)pstrcat( s, saved_ext );
620       SAFE_FREE(saved_ext);
621     }
622     return( False );
623   }
624
625   /* If we *did* find it, we need to copy it into the string buffer. */
626   found_name = (char *)(FoundPtr + 1);
627   found_name += (strlen( found_name ) + 1);
628
629   DEBUG( 3, ("Found %s on mangled stack ", s) );
630
631   (void)pstrcpy( s, found_name );
632   if( saved_ext )
633   {
634     /* Replace the saved_ext as it was truncated. */
635     (void)pstrcat( s, saved_ext );
636     SAFE_FREE(saved_ext);
637   }
638
639   DEBUG( 3, ("as %s\n", s) );
640
641   return( True );
642 } /* check_mangled_cache */
643
644
645 /* ************************************************************************** **
646  * Used only in do_fwd_mangled_map(), below.
647  * ************************************************************************** **
648  */
649 static char *map_filename( char *s,         /* This is null terminated */
650                            char *pattern,   /* This isn't. */
651                            int len )        /* This is the length of pattern. */
652   {
653   static pstring matching_bit;  /* The bit of the string which matches */
654                                 /* a * in pattern if indeed there is a * */
655   char *sp;                     /* Pointer into s. */
656   char *pp;                     /* Pointer into p. */
657   char *match_start;            /* Where the matching bit starts. */
658   pstring pat;
659
660   StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */
661   pstrcpy( matching_bit, "" );  /* Match but no star gets this. */
662   pp = pat;                     /* Initialize the pointers. */
663   sp = s;
664
665   if( strequal(s, ".") || strequal(s, ".."))
666     {
667     return NULL;                /* Do not map '.' and '..' */
668     }
669
670   if( (len == 1) && (*pattern == '*') )
671     {
672     return NULL;                /* Impossible, too ambiguous for */
673     }                           /* words! */
674
675   while( (*sp)                  /* Not the end of the string. */
676       && (*pp)                  /* Not the end of the pattern. */
677       && (*sp == *pp)           /* The two match. */
678       && (*pp != '*') )         /* No wildcard. */
679     {
680     sp++;                       /* Keep looking. */
681     pp++;
682     }
683
684   if( !*sp && !*pp )            /* End of pattern. */
685     return( matching_bit );     /* Simple match.  Return empty string. */
686
687   if( *pp == '*' )
688     {
689     pp++;                       /* Always interrested in the chacter */
690                                 /* after the '*' */
691     if( !*pp )                  /* It is at the end of the pattern. */
692       {
693       StrnCpy( matching_bit, s, sp-s );
694       return( matching_bit );
695       }
696     else
697       {
698       /* The next character in pattern must match a character further */
699       /* along s than sp so look for that character. */
700       match_start = sp;
701       while( (*sp)              /* Not the end of s. */
702           && (*sp != *pp) )     /* Not the same  */
703         sp++;                   /* Keep looking. */
704       if( !*sp )                /* Got to the end without a match. */
705         {
706         return( NULL );
707         }                       /* Still hope for a match. */
708       else
709         {
710         /* Now sp should point to a matching character. */
711         StrnCpy(matching_bit, match_start, sp-match_start);
712         /* Back to needing a stright match again. */
713         while( (*sp)            /* Not the end of the string. */
714             && (*pp)            /* Not the end of the pattern. */
715             && (*sp == *pp) )   /* The two match. */
716           {
717           sp++;                 /* Keep looking. */
718           pp++;
719           }
720         if( !*sp && !*pp )      /* Both at end so it matched */
721           return( matching_bit );
722         else
723           return( NULL );
724         }
725       }
726     }
727   return( NULL );               /* No match. */
728   } /* map_filename */
729
730
731 /* ************************************************************************** **
732  * MangledMap is a series of name pairs in () separated by spaces.
733  * If s matches the first of the pair then the name given is the
734  * second of the pair.  A * means any number of any character and if
735  * present in the second of the pair as well as the first the
736  * matching part of the first string takes the place of the * in the
737  * second.
738  *
739  * I wanted this so that we could have RCS files which can be used
740  * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
741  * converts the UNIX RCS file subdirectory to lowercase thus
742  * preventing mangling.
743  *
744  * (I think Andrew wrote the above, but I'm not sure. -- CRH)
745  *
746  * See 'mangled map' in smb.conf(5).
747  *
748  * ************************************************************************** **
749  */
750 static void do_fwd_mangled_map(char *s, char *MangledMap)
751   {
752   char *start=MangledMap;       /* Use this to search for mappings. */
753   char *end;                    /* Used to find the end of strings. */
754   char *match_string;
755   pstring new_string;           /* Make up the result here. */
756   char *np;                     /* Points into new_string. */
757
758   DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) );
759   while( *start )
760     {
761     while( (*start) && (*start != '(') )
762       start++;
763     if( !*start )
764       continue;                 /* Always check for the end. */
765     start++;                    /* Skip the ( */
766     end = start;                /* Search for the ' ' or a ')' */
767     DEBUG( 5, ("Start of first in pair '%s'\n", start) );
768     while( (*end) && !((*end == ' ') || (*end == ')')) )
769       end++;
770     if( !*end )
771       {
772       start = end;
773       continue;                 /* Always check for the end. */
774       }
775     DEBUG( 5, ("End of first in pair '%s'\n", end) );
776     if( (match_string = map_filename( s, start, end-start )) )
777       {
778       DEBUG( 5, ("Found a match\n") );
779       /* Found a match. */
780       start = end + 1;          /* Point to start of what it is to become. */
781       DEBUG( 5, ("Start of second in pair '%s'\n", start) );
782       end = start;
783       np = new_string;
784       while( (*end)             /* Not the end of string. */
785           && (*end != ')')      /* Not the end of the pattern. */
786           && (*end != '*') )    /* Not a wildcard. */
787         *np++ = *end++;
788       if( !*end )
789         {
790         start = end;
791         continue;               /* Always check for the end. */
792         }
793       if( *end == '*' )
794         {
795         pstrcpy( np, match_string );
796         np += strlen( match_string );
797         end++;                  /* Skip the '*' */
798         while( (*end)             /* Not the end of string. */
799             && (*end != ')')      /* Not the end of the pattern. */
800             && (*end != '*') )    /* Not a wildcard. */
801           *np++ = *end++;
802         }
803       if( !*end )
804         {
805         start = end;
806         continue;               /* Always check for the end. */
807         }
808       *np++ = '\0';             /* NULL terminate it. */
809       DEBUG(5,("End of second in pair '%s'\n", end));
810       pstrcpy( s, new_string );  /* Substitute with the new name. */
811       DEBUG( 5, ("s is now '%s'\n", s) );
812       }
813     start = end;              /* Skip a bit which cannot be wanted anymore. */
814     start++;
815     }
816   } /* do_fwd_mangled_map */
817
818 /*****************************************************************************
819  * do the actual mangling to 8.3 format
820  * the buffer must be able to hold 13 characters (including the null)
821  *****************************************************************************
822  */
823 void mangle_name_83( char *s)
824   {
825   int csum;
826   char *p;
827   char extension[4];
828   char base[9];
829   int baselen = 0;
830   int extlen = 0;
831
832   extension[0] = 0;
833   base[0] = 0;
834
835   p = strrchr_m(s,'.');  
836   if( p && (strlen(p+1) < (size_t)4) )
837     {
838     BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
839
840     if( all_normal && p[1] != 0 )
841       {
842       *p = 0;
843       csum = str_checksum( s );
844       *p = '.';
845       }
846     else
847       csum = str_checksum(s);
848     }
849   else
850     csum = str_checksum(s);
851
852   strupper( s );
853
854   DEBUG( 5, ("Mangling name %s to ",s) );
855
856   if( p )
857     {
858     if( p == s )
859       safe_strcpy( extension, "___", 3 );
860     else
861       {
862       *p++ = 0;
863       while( *p && extlen < 3 )
864         {
865             if( /*isdoschar (*p) &&*/ *p != '.' )
866               extension[extlen++] = p[0];
867             p++;
868         }
869       extension[extlen] = 0;
870       }
871     }
872
873   p = s;
874
875   while( *p && baselen < 5 )
876     {
877         if( /*isdoschar( *p ) &&*/ *p != '.' )
878           base[baselen++] = p[0];
879         p++;
880     }
881   base[baselen] = 0;
882
883   csum = csum % (MANGLE_BASE*MANGLE_BASE);
884
885   (void)slprintf(s, 12, "%s%c%c%c",
886                  base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
887
888   if( *extension )
889     {
890     (void)pstrcat( s, "." );
891     (void)pstrcat( s, extension );
892     }
893
894   DEBUG( 5, ( "%s\n", s ) );
895
896   } /* mangle_name_83 */
897
898 /*****************************************************************************
899  * Convert a filename to DOS format.  Return True if successful.
900  *
901  *  Input:  OutName - Source *and* destination buffer. 
902  *
903  *                    NOTE that OutName must point to a memory space that
904  *                    is at least 13 bytes in size!
905  *
906  *          need83  - If False, name mangling will be skipped unless the
907  *                    name contains illegal characters.  Mapping will still
908  *                    be done, if appropriate.  This is probably used to
909  *                    signal that a client does not require name mangling,
910  *                    thus skipping the name mangling even on shares which
911  *                    have name-mangling turned on.
912  *          cache83 - If False, the mangled name cache will not be updated.
913  *                    This is usually used to prevent that we overwrite
914  *                    a conflicting cache entry prematurely, i.e. before
915  *                    we know whether the client is really interested in the
916  *                    current name.  (See PR#13758).  UKD.
917  *          snum    - Share number.  This identifies the share in which the
918  *                    name exists.
919  *
920  *  Output: Returns False only if the name wanted mangling but the share does
921  *          not have name mangling turned on.
922  *
923  * ****************************************************************************
924  */
925 BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
926 {
927         char *map;
928         DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
929                 need83 ? "TRUE" : "FALSE", cache83 ? "TRUE" : "FALSE", snum));
930
931 #ifdef MANGLE_LONG_FILENAMES
932         if( !need83 && is_illegal_name(OutName) )
933                 need83 = True;
934 #endif  
935
936         /* apply any name mappings */
937         map = lp_mangled_map(snum);
938
939         if (map && *map) {
940                 do_fwd_mangled_map( OutName, map );
941         }
942
943         /* check if it's already in 8.3 format */
944         if (need83 && !is_8_3(OutName, True)) {
945                 char *tmp = NULL; 
946
947                 if (!lp_manglednames(snum)) {
948                         return(False);
949                 }
950
951                 /* mangle it into 8.3 */
952                 if (cache83)
953                         tmp = strdup(OutName);
954
955                 mangle_name_83(OutName);
956
957                 if(tmp != NULL) {
958                         cache_mangled_name(OutName, tmp);
959                         SAFE_FREE(tmp);
960                 }
961         }
962
963         DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
964         return(True);
965 } /* name_map_mangle */
966
967
968
969
970
971 #if 0
972 #define MANGLE_TDB_VERSION              "20010927"
973 #define MANGLE_TDB_FILE_NAME            "mangle.tdb"
974 #define MANGLED_PREFIX                  "MANGLED_"
975 #define LONG_PREFIX                     "LONG_"
976 #define COUNTER_PREFIX                  "COUNTER_"
977 #define MANGLE_COUNTER_MAX              99
978 #define MANGLE_SUFFIX_SIZE              2
979
980
981 struct mt_enum_info {
982         TDB_CONTEXT     *mangle_tdb;
983         TDB_DATA        key;
984 };
985
986
987 static struct mt_enum_info      global_mt_ent = {0, 0};
988
989 static int POW10(unsigned int exp)
990 {
991         int result = 1;
992         
993         while (exp) {
994                 result *= 10;
995                 exp--;
996         }
997   
998         return result;
999 }
1000
1001 static BOOL init_mangle_tdb(void)
1002 {
1003         char *tdbfile;
1004         
1005         if (global_mt_ent.mangle_tdb == 0)
1006         {
1007                 tdbfile = lock_path(MANGLE_TDB_FILE_NAME); /* this return a static pstring do not try to free it */
1008
1009                 /* Open tdb */
1010                 if (!(global_mt_ent.mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600)))
1011                 {
1012                         DEBUG(0, ("Unable to open Mangle TDB\n"));
1013                         return False;
1014                 }
1015         }
1016
1017         return True;
1018 }
1019
1020 /* see push_ucs2 */
1021 int dos_to_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
1022 {
1023         int len=0;
1024         int src_len = strlen(src);
1025         pstring tmpbuf;
1026
1027         /* treat a pstring as "unlimited" length */
1028         if (dest_len == -1) {
1029                 dest_len = sizeof(pstring);
1030         }
1031
1032         if (flags & STR_UPPER) {
1033                 pstrcpy(tmpbuf, src);
1034                 strupper(tmpbuf);
1035                 src = tmpbuf;
1036         }
1037
1038         if (flags & STR_TERMINATE) {
1039                 src_len++;
1040         }
1041
1042         if (ucs2_align(base_ptr, dest, flags)) {
1043                 *(char *)dest = 0;
1044                 dest = (void *)((char *)dest + 1);
1045                 if (dest_len) dest_len--;
1046                 len++;
1047         }
1048
1049         /* ucs2 is always a multiple of 2 bytes */
1050         dest_len &= ~1;
1051
1052         len += convert_string(CH_DOS, CH_UCS2, src, src_len, dest, dest_len);
1053         return len;
1054 }
1055
1056 /* see pull_ucs2 */
1057 int ucs2_to_dos(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
1058 {
1059         int ret;
1060
1061         if (dest_len == -1) {
1062                 dest_len = sizeof(pstring);
1063         }
1064
1065         if (ucs2_align(base_ptr, src, flags)) {
1066                 src = (const void *)((char *)src + 1);
1067                 if (src_len > 0) src_len--;
1068         }
1069
1070         if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
1071
1072         /* ucs2 is always a multiple of 2 bytes */
1073         src_len &= ~1;
1074         
1075         ret = convert_string(CH_UCS2, CH_DOS, src, src_len, dest, dest_len);
1076         if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
1077
1078         return src_len;
1079 }
1080
1081 /* return False if something fail and
1082  * return 2 alloced unicode strings that contain prefix and extension
1083  */
1084 static BOOL mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, smb_ucs2_t **extension)
1085 {
1086         size_t str_len;
1087         smb_ucs2_t *p;
1088
1089         *extension = 0;
1090         *prefix = strdup_w(ucs2_string);
1091         if (!*prefix)
1092         {
1093                 DEBUG(0,("mangle_get_prefix: out of memory!\n"));
1094                 return False;
1095         }
1096         str_len = strlen_w(*prefix);
1097         if (p = strrchr_wa(*prefix, '.'))
1098         {
1099         /* TODO: check it is <4 in dos charset */
1100                 if ((str_len - ((p - *prefix) / sizeof(smb_ucs2_t))) < 4) /* check extension */
1101                 {
1102                         *p = 0;
1103                         p++;
1104                         *extension = strdup_w(p);
1105                         if (!*extension)
1106                         {
1107                                 DEBUG(0,("mangle_get_prefix: out of memory!\n"));
1108                                 SAFE_FREE(*prefix);
1109                                 return False;
1110                         }
1111                 }
1112         }
1113
1114         return True;
1115 }
1116
1117
1118 /* mangled must contain only the file name, not a path.
1119    and MUST be ZERO terminated */
1120 smb_ucs2_t *unmangle(const smb_ucs2_t *mangled)
1121 {
1122         TDB_DATA data, key;
1123         fstring keystr;
1124         fstring mufname;
1125         smb_ucs2_t *pref, *ext, *retstr;
1126         size_t long_len, ext_len;
1127         BOOL ret;
1128
1129         if (strlen_w(mangled) > 12) return NULL;
1130         if (!strchr_wa(mangled, '~')) return NULL;
1131         if (!init_mangle_tdb()) return NULL;
1132         
1133         ret = mangle_get_prefix(mangled, &pref, &ext);
1134         if (!ret) return NULL;
1135         
1136         /* TODO: get out extension */
1137         strlower_w(pref);
1138         /* set search key */
1139         ucs2_to_dos(NULL, mufname, pref, sizeof(mufname), 0, STR_TERMINATE);
1140         SAFE_FREE(pref);
1141         slprintf(keystr, sizeof(keystr) - 1, "%s%s", MANGLED_PREFIX, mufname);
1142         key.dptr = keystr;
1143         key.dsize = strlen (keystr) + 1;
1144         
1145         /* get the record */
1146         data = tdb_fetch(global_mt_ent.mangle_tdb, key);
1147         
1148         if (!data.dptr) /* not found */
1149         {
1150                 DEBUG(5,("unmangle: failed retrieve from db %s\n", tdb_errorstr(global_mt_ent.mangle_tdb)));
1151                 retstr = NULL;
1152                 goto done;
1153         }
1154
1155         if (ext)
1156         {
1157                 long_len = data.dsize / 2; /* terminator counted on purpose, will contain '.' */
1158                 ext_len = strlen_w(ext);
1159                 retstr = (smb_ucs2_t *)malloc((long_len + ext_len + 1)*sizeof(smb_ucs2_t));
1160                 if (!retstr)
1161                 {
1162                         DEBUG(0, ("unamngle: out of memory!\n"));
1163                         goto done;
1164                 }
1165                 strncpy_w(retstr, (smb_ucs2_t *)data.dptr, long_len);
1166                 retstr[long_len] = UCS2_CHAR('.');
1167                 retstr[long_len + 1] = 0;
1168                 strncat_w(retstr, ext, ext_len);
1169         }
1170         else
1171         {
1172                 retstr = strdup_w((smb_ucs2_t *)data.dptr);
1173                 if (!retstr)
1174                 {
1175                         DEBUG(0, ("unamngle: out of memory!\n"));
1176                         goto done;
1177                 }
1178
1179         }
1180
1181 done:
1182         SAFE_FREE(data.dptr);
1183         SAFE_FREE(pref);
1184         SAFE_FREE(ext);
1185
1186         return retstr;
1187 }
1188
1189 /* unmangled must contain only the file name, not a path.
1190    and MUST be ZERO terminated */
1191 smb_ucs2_t *_mangle(const smb_ucs2_t *unmangled)
1192 {
1193         TDB_DATA data, key, klock;
1194         pstring keystr;
1195         pstring longname;
1196         fstring keylock;
1197         fstring mufname;
1198         fstring prefix;
1199         BOOL tclock = False;
1200         char suffix[MANGLE_SUFFIX_SIZE + 1];
1201         smb_ucs2_t *mangled = NULL;
1202         smb_ucs2_t *um, *ext, *p = NULL;
1203         smb_ucs2_t temp[8];
1204         size_t pref_len, ext_len;
1205         size_t um_len;
1206         uint32 n, c, pos;
1207
1208         if (!init_mangle_tdb()) return NULL;
1209
1210         /* TODO: if it is a path return a failure ?? */
1211         if (!mangle_get_prefix(unmangled, &um, &ext)) return NULL;
1212
1213         /* test if the same is yet mangled */
1214
1215         /* set search key */
1216         pull_ucs2(NULL, longname, um, sizeof(longname), 0, STR_TERMINATE);
1217         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
1218         key.dptr = keystr;
1219         key.dsize = strlen(keystr) + 1;
1220
1221         /* get the record */
1222         data = tdb_fetch (global_mt_ent.mangle_tdb, key);
1223         if (!data.dptr) /* not found */
1224         {
1225                 if (tdb_error(global_mt_ent.mangle_tdb) != TDB_ERR_NOEXIST)
1226                 {
1227                         DEBUG(0, ("mangle: database retrieval error: %s\n",
1228                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1229                         goto done;
1230                 }
1231
1232                 /* if not find the first free possibile mangled name */
1233
1234                 n = 0;
1235                 do
1236                 {
1237                         n++;
1238                         pos = 8 - n - MANGLE_SUFFIX_SIZE;
1239                         if (pos == 0)
1240                         {
1241                                 DEBUG(0, ("mangle: unable to mangle file name!\n"));
1242                                 goto done;
1243                         }
1244                         strncpy_w(temp, um, pos);
1245                         strlower_w(temp);
1246
1247                         ucs2_to_dos(NULL, prefix, temp, sizeof(prefix), 0, STR_TERMINATE);
1248                 }
1249                 while (strlen(prefix) > 8 - (MANGLE_SUFFIX_SIZE + 1));
1250
1251                 slprintf(keylock, sizeof(keylock)-1, "%s%s", COUNTER_PREFIX, prefix);
1252                 klock.dptr = keylock;
1253                 klock.dsize = strlen(keylock) + 1;
1254
1255                 c = 0;
1256                 data.dptr = (char *)&c;
1257                 data.dsize = sizeof(uint32);
1258                 /* try to insert a new counter prefix, if it exist the call will
1259                    fail (correct) otherwise it will create a new entry with counter set
1260                    to 0
1261                  */
1262                 tdb_store(global_mt_ent.mangle_tdb, klock, data, TDB_INSERT);
1263
1264                 /* lock the mangle counter for this prefix */           
1265                 if (!tdb_chainlock(global_mt_ent.mangle_tdb, klock))
1266                 {
1267                         DEBUG(0,("mangle: failed to lock database\n!"));
1268                         goto done;
1269                 }
1270                 tclock = True;
1271
1272                 data = tdb_fetch(global_mt_ent.mangle_tdb, klock);
1273                 if (!data.dptr)
1274                 {
1275                         DEBUG(0, ("mangle: database retrieval error: %s\n",
1276                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1277                         goto done;
1278                 }
1279                 c = *((uint32 *)data.dptr);
1280                 c++;
1281                         
1282                 temp[pos] = UCS2_CHAR('~');
1283                 temp[pos+1] = 0;
1284                 snprintf(suffix, MANGLE_SUFFIX_SIZE + 1, "%.6d", c);
1285                 strncat_wa(temp, &suffix[6 - MANGLE_SUFFIX_SIZE], MANGLE_SUFFIX_SIZE + 1);
1286
1287                 ucs2_to_dos(NULL, mufname, temp, sizeof(mufname), 0, STR_TERMINATE);
1288                 if (strlen(mufname) > 8)
1289                 {
1290                         DEBUG(0, ("mangle: darn, logic error aborting!\n"));
1291                         goto done;
1292                 }
1293                         
1294                 /* store the long entry with mangled key */
1295                 slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
1296                 key.dptr = keystr;
1297                 key.dsize = strlen (keystr) + 1;
1298                 data.dsize = (strlen_w(um) + 1) * sizeof (smb_ucs2_t);
1299                 data.dptr = (void *)um;
1300
1301                 if (tdb_store(global_mt_ent.mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
1302                 {
1303                         DEBUG(0, ("mangle: database store error: %s\n",
1304                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1305                         goto done;
1306                 }
1307
1308                 /* store the mangled entry with long key*/
1309                 pull_ucs2(NULL, longname, um, sizeof(longname), 0, STR_TERMINATE);
1310                 slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
1311                 key.dptr = keystr;
1312                 key.dsize = strlen (keystr) + 1;
1313                 data.dsize = strlen(mufname +1);
1314                 data.dptr = mufname;
1315                 if (tdb_store(global_mt_ent.mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
1316                 {
1317                         DEBUG(0, ("mangle: store failed: %s\n",
1318                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1319
1320                         /* try to delete the mangled key entry to avoid later inconsistency */
1321                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
1322                         key.dptr = keystr;
1323                         key.dsize = strlen (keystr) + 1;
1324                         if (!tdb_delete(global_mt_ent.mangle_tdb, key))
1325                         {
1326                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
1327                         }
1328                         goto done;
1329                 }
1330
1331                 p = strdup_w(temp);
1332                 if (!p)
1333                 {
1334                         DEBUG(0,("mangle: out of memory!\n"));
1335                         goto done;
1336                 }
1337                 
1338                 data.dptr = (char *)&c;
1339                 data.dsize = sizeof(uint32);
1340                 if(!tdb_store(global_mt_ent.mangle_tdb, klock, data, TDB_INSERT))
1341                 {
1342                         DEBUG(0, ("mangle: store failed: %s\n",
1343                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1344                         /* try to delete the mangled and long key entry to avoid later inconsistency */
1345                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
1346                         key.dptr = keystr;
1347                         key.dsize = strlen (keystr) + 1;
1348                         if (!tdb_delete(global_mt_ent.mangle_tdb, key))
1349                         {
1350                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
1351                         }
1352                         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
1353                         key.dptr = keystr;
1354                         key.dsize = strlen (keystr) + 1;
1355                         if (!tdb_delete(global_mt_ent.mangle_tdb, key))
1356                         {
1357                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
1358                         }
1359                         goto done;
1360                 }
1361
1362                 tclock = False;
1363                 tdb_chainunlock(global_mt_ent.mangle_tdb, klock);
1364         }
1365         else /* FOUND */
1366         {
1367                 p = (smb_ucs2_t *)malloc(data.dsize*sizeof(smb_ucs2_t));
1368                 if (!p)
1369                 {
1370                         DEBUG(0,("mangle: out of memory!\n"));
1371                         goto done;
1372                 }
1373                 dos_to_ucs2(NULL, p, data.dptr, data.dsize*sizeof(smb_ucs2_t), STR_TERMINATE);
1374         }
1375                 
1376         if (ext)
1377         {
1378                 pref_len = strlen_w(p) + 1; /* terminator counted on purpose, will contain '.' */
1379                 ext_len = strlen_w(ext);
1380                 mangled = (smb_ucs2_t *)malloc((pref_len + ext_len + 1)*sizeof(smb_ucs2_t));
1381                 if (!mangled)
1382                 {
1383                         DEBUG(0,("mangle: out of memory!\n"));
1384                         goto done;
1385                 }
1386                 strncpy_w (mangled, p, pref_len);
1387                 mangled[pref_len] = UCS2_CHAR('.');
1388                 mangled[pref_len + 1] = 0;
1389                 strncat_w (mangled, ext, ext_len);
1390         }
1391         else
1392         {
1393                 mangled = strdup_w(p);
1394                 if (!mangled)
1395                 {
1396                         DEBUG(0,("mangle: out of memory!\n"));
1397                         goto done;
1398                 }
1399         }
1400
1401 done:
1402         if (tclock) tdb_chainunlock(global_mt_ent.mangle_tdb, klock);
1403         SAFE_FREE(p);
1404         SAFE_FREE(um);
1405         SAFE_FREE(ext);
1406
1407         return mangled;
1408 }
1409
1410 #endif /* 0 */
1411
1412 #ifdef TEST_MANGLE_CODE
1413
1414 #define LONG            "this_is_a_long_file_name"
1415 #define LONGM           "this_~01"
1416 #define SHORT           "short"
1417 #define SHORTM          "short~01"
1418 #define EXT1            "ex1"
1419 #define EXT2            "e2"
1420 #define EXT3            "3"
1421 #define EXTFAIL         "longext"
1422
1423 static void unmangle_test (char *name, char *ext)
1424 {
1425         smb_ucs2_t ucs2_name[2048];
1426         smb_ucs2_t *retstr;
1427         pstring unix_name;      
1428
1429         push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
1430         if (ext)
1431         {
1432                 strncat_wa(ucs2_name, ".", 1);
1433                 strncat_wa(ucs2_name, ext, strlen(ext));
1434         }
1435         retstr = unmangle(ucs2_name);
1436         if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
1437         else unix_name[0] = 0;
1438         if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
1439         else printf ("[%s] ---> [%s]\n", name, unix_name);
1440         SAFE_FREE(retstr);
1441 }
1442
1443 static void mangle_test (char *name, char *ext)
1444 {
1445         smb_ucs2_t ucs2_name[2048];
1446         smb_ucs2_t *retstr;
1447         pstring unix_name;      
1448
1449         push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
1450         if (ext)
1451         {
1452                 strncat_wa(ucs2_name, ".", 1);
1453                 strncat_wa(ucs2_name, ext, strlen(ext));
1454         }
1455         retstr = _mangle(ucs2_name);
1456         if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
1457         else unix_name[0] = 0;
1458         if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
1459         else printf ("[%s] ---> [%s]\n", name, unix_name);
1460         SAFE_FREE(retstr);
1461 }
1462
1463 void mangle_test_code(void)
1464 {
1465         /* unmangle every */
1466         unmangle_test (LONG, NULL);
1467         unmangle_test (LONG, EXT1);
1468         unmangle_test (LONG, EXT2);
1469         unmangle_test (LONG, EXT3);
1470         unmangle_test (LONG, EXTFAIL);
1471
1472         unmangle_test (LONGM, NULL);
1473         unmangle_test (LONGM, EXT1);
1474         unmangle_test (LONGM, EXT2);
1475         unmangle_test (LONGM, EXT3);
1476         unmangle_test (LONGM, EXTFAIL);
1477
1478         unmangle_test (SHORT, NULL);
1479         unmangle_test (SHORT, EXT1);
1480         unmangle_test (SHORT, EXT2);
1481         unmangle_test (SHORT, EXT3);
1482         unmangle_test (SHORT, EXTFAIL);
1483
1484         unmangle_test (SHORTM, NULL);
1485         unmangle_test (SHORTM, EXT1);
1486         unmangle_test (SHORTM, EXT2);
1487         unmangle_test (SHORTM, EXT3);
1488         unmangle_test (SHORTM, EXTFAIL);
1489
1490         /* mangle every */
1491         mangle_test (LONG, NULL);
1492         mangle_test (LONG, EXT1);
1493         mangle_test (LONG, EXT2);
1494         mangle_test (LONG, EXT3);
1495         mangle_test (LONG, EXTFAIL);
1496
1497         mangle_test (LONGM, NULL);
1498         mangle_test (LONGM, EXT1);
1499         mangle_test (LONGM, EXT2);
1500         mangle_test (LONGM, EXT3);
1501         mangle_test (LONGM, EXTFAIL);
1502
1503         mangle_test (SHORT, NULL);
1504         mangle_test (SHORT, EXT1);
1505         mangle_test (SHORT, EXT2);
1506         mangle_test (SHORT, EXT3);
1507         mangle_test (SHORT, EXTFAIL);
1508
1509         mangle_test (SHORTM, NULL);
1510         mangle_test (SHORTM, EXT1);
1511         mangle_test (SHORTM, EXT2);
1512         mangle_test (SHORTM, EXT3);
1513         mangle_test (SHORTM, EXTFAIL);
1514
1515         /* unmangle again every */
1516         unmangle_test (LONG, NULL);
1517         unmangle_test (LONG, EXT1);
1518         unmangle_test (LONG, EXT2);
1519         unmangle_test (LONG, EXT3);
1520         unmangle_test (LONG, EXTFAIL);
1521
1522         unmangle_test (LONGM, NULL);
1523         unmangle_test (LONGM, EXT1);
1524         unmangle_test (LONGM, EXT2);
1525         unmangle_test (LONGM, EXT3);
1526         unmangle_test (LONGM, EXTFAIL);
1527
1528         unmangle_test (SHORT, NULL);
1529         unmangle_test (SHORT, EXT1);
1530         unmangle_test (SHORT, EXT2);
1531         unmangle_test (SHORT, EXT3);
1532         unmangle_test (SHORT, EXTFAIL);
1533
1534         unmangle_test (SHORTM, NULL);
1535         unmangle_test (SHORTM, EXT1);
1536         unmangle_test (SHORTM, EXT2);
1537         unmangle_test (SHORTM, EXT3);
1538         unmangle_test (SHORTM, EXTFAIL);
1539 }
1540
1541 #endif /* TEST_MANGLE_CODE */