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