Removed version number from file header.
[samba.git] / source3 / smbd / mangle.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Name mangling with persistent tdb
4    Copyright (C) Simo Sorce 2001
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /****************************************************************************
22   Rewritten from scrach in 2001 by Simo Sorce <idra@samba.org>
23  ****************************************************************************/
24
25 #include "includes.h"
26
27
28 /* -------------------------------------------------------------------------- **
29  * External Variables...
30  */
31
32 extern int case_default;    /* Are conforming 8.3 names all upper or lower?   */
33 extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
34
35 char magic_char = '~';
36
37 /* -------------------------------------------------------------------- */
38
39 #define MANGLE_TDB_VERSION              "20010927"
40 #define MANGLE_TDB_FILE_NAME            "mangle.tdb"
41 #define MANGLED_PREFIX                  "MANGLED_"
42 #define LONG_PREFIX                     "LONG_"
43 #define COUNTER_PREFIX                  "COUNTER_"
44 #define MANGLE_COUNTER_MAX              99
45 #define MANGLE_SUFFIX_SIZE              3 /* "~XX" */
46
47
48 static TDB_CONTEXT      *mangle_tdb;
49
50 BOOL init_mangle_tdb(void)
51 {
52         char *tdbfile;
53         
54         tdbfile = lock_path(MANGLE_TDB_FILE_NAME); /* this return a static pstring do not try to free it */
55
56         /* Open tdb */
57         if (!(mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600)))
58         {
59                 DEBUG(0, ("Unable to open Mangle TDB\n"));
60                 return False;
61         }
62
63         return True;
64 }
65
66 /* trasform a unicode string into a dos charset string */
67 static int ucs2_to_dos(char *dest, const smb_ucs2_t *src, int dest_len)
68 {
69         int src_len, ret;
70
71         if (dest_len == -1) {
72                 dest_len = sizeof(pstring);
73         }
74
75         src_len = strlen_w(src)* sizeof(smb_ucs2_t);
76         
77         ret = convert_string(CH_UCS2, CH_DOS, src, src_len, dest, dest_len);
78         if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
79
80         return ret;
81 }
82
83 /* trasform in a string that contain only valid chars for win filenames,
84  not including a '.' */
85 static void strvalid(smb_ucs2_t *src)
86 {
87         if (!src || !*src) return;
88
89         while (*src) {
90                 if (!isvalid83_w(*src) || *src == UCS2_CHAR('.')) *src = UCS2_CHAR('_');
91                 src++;
92         }
93 }
94
95
96 /* return False if something fail and
97  * return 2 alloced unicode strings that contain prefix and extension
98  */
99 static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, smb_ucs2_t **extension)
100 {
101         size_t ext_len;
102         smb_ucs2_t *p;
103
104         *extension = 0;
105         *prefix = strdup_w(ucs2_string);
106         if (!*prefix)
107         {
108                 DEBUG(0,("mangle_get_prefix: out of memory!\n"));
109                 return NT_STATUS_NO_MEMORY;
110         }
111         if ((p = strrchr_w(*prefix, UCS2_CHAR('.'))))
112         {
113                 ext_len = strlen_w(p+1);
114                 if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) &&
115                     (NT_STATUS_IS_OK(has_valid_chars(p+1)))) /* check extension */
116                 {
117                         *p = 0;
118                         *extension = strdup_w(p+1);
119                         if (!*extension)
120                         {
121                                 DEBUG(0,("mangle_get_prefix: out of memory!\n"));
122                                 SAFE_FREE(*prefix);
123                                 return NT_STATUS_NO_MEMORY;
124                         }
125                 }
126         }
127         return NT_STATUS_OK;
128 }
129
130
131 /* mangled must contain only the file name, not a path.
132    and MUST be ZERO terminated */
133 smb_ucs2_t *unmangle(const smb_ucs2_t *mangled)
134 {
135         TDB_DATA data, key;
136         fstring keystr;
137         fstring mufname;
138         smb_ucs2_t *pref, *ext, *retstr;
139         size_t long_len, ext_len, muf_len;
140
141         if (strlen_w(mangled) > 12) return NULL;
142         if (!strchr_w(mangled, UCS2_CHAR('~'))) return NULL;
143
144         /* if it is a path refuse to proceed */
145         if (strchr_w(mangled, UCS2_CHAR('/'))) {
146                 DEBUG(10, ("unmangle: cannot unmangle a path\n"));
147                 return NULL;
148         }
149
150         if (NT_STATUS_IS_ERR(mangle_get_prefix(mangled, &pref, &ext)))
151                 return NULL;
152
153         /* mangled names are stored lowercase only */   
154         strlower_w(pref);
155         /* set search key */
156         muf_len = ucs2_to_dos(mufname, pref, sizeof(mufname));
157         SAFE_FREE(pref);
158         if (!muf_len) return NULL;
159         
160         slprintf(keystr, sizeof(keystr) - 1, "%s%s", MANGLED_PREFIX, mufname);
161         key.dptr = keystr;
162         key.dsize = strlen (keystr) + 1;
163         
164         /* get the record */
165         data = tdb_fetch(mangle_tdb, key);
166         
167         if (!data.dptr) /* not found */
168         {
169                 DEBUG(5,("unmangle: failed retrieve from db %s\n", tdb_errorstr(mangle_tdb)));
170                 retstr = NULL;
171                 goto done;
172         }
173
174         if (ext)
175         {
176                 long_len = (data.dsize / 2) - 1;
177                 ext_len = strlen_w(ext);
178                 retstr = (smb_ucs2_t *)malloc((long_len + ext_len + 2)*sizeof(smb_ucs2_t));
179                 if (!retstr)
180                 {
181                         DEBUG(0, ("unamngle: out of memory!\n"));
182                         goto done;
183                 }
184                 strncpy_w(retstr, (smb_ucs2_t *)data.dptr, long_len);
185                 retstr[long_len] = UCS2_CHAR('.');
186                 retstr[long_len + 1] = 0;
187                 strncat_w(retstr, ext, ext_len);
188         }
189         else
190         {
191                 retstr = strdup_w((smb_ucs2_t *)data.dptr);
192                 if (!retstr)
193                 {
194                         DEBUG(0, ("unamngle: out of memory!\n"));
195                         goto done;
196                 }
197
198         }
199
200 done:
201         SAFE_FREE(data.dptr);
202         SAFE_FREE(pref);
203         SAFE_FREE(ext);
204
205         return retstr;
206 }
207
208 /* unmangled must contain only the file name, not a path.
209    and MUST be ZERO terminated.
210    return a new allocated string if the name is yet valid 8.3
211    or is mangled successfully.
212    return null on error.
213  */
214
215 smb_ucs2_t *mangle(const smb_ucs2_t *unmangled)
216 {
217         TDB_DATA data, key, klock;
218         pstring keystr;
219         pstring longname;
220         fstring keylock;
221         fstring mufname;
222         fstring prefix;
223         BOOL tclock = False;
224         char suffix[7];
225         smb_ucs2_t *mangled = NULL;
226         smb_ucs2_t *umpref, *ext, *p = NULL;
227         size_t pref_len, ext_len, ud83_len;
228
229         /* if it is a path refuse to proceed */
230         if (strchr_w(unmangled, UCS2_CHAR('/'))) {
231                 DEBUG(10, ("mangle: cannot mangle a path\n"));
232                 return NULL;
233         }
234
235         /* if it is a valid 8_3 do not mangle again */
236         if (NT_STATUS_IS_OK(is_8_3_w(unmangled)))
237                 return NULL;
238
239         if (NT_STATUS_IS_ERR(mangle_get_prefix(unmangled, &umpref, &ext)))
240                 return NULL;
241
242         /* test if the same is yet mangled */
243
244         /* set search key */
245         pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
246         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
247         key.dptr = keystr;
248         key.dsize = strlen(keystr) + 1;
249
250         /* get the record */
251         data = tdb_fetch (mangle_tdb, key);
252         if (!data.dptr) /* not found */
253         {
254                 smb_ucs2_t temp[9];
255                 size_t c, pos;
256
257                 if (tdb_error(mangle_tdb) != TDB_ERR_NOEXIST)
258                 {
259                         DEBUG(0, ("mangle: database retrieval error: %s\n",
260                                         tdb_errorstr(mangle_tdb)));
261                         goto done;
262                 }
263
264                 /* if not find the first free possibile mangled name */
265
266                 pos = strlen_w(umpref);
267                 if ((8 - MANGLE_SUFFIX_SIZE) < pos)
268                         pos = 8 - MANGLE_SUFFIX_SIZE;
269                 pos++;
270                 do
271                 {
272                         pos--;
273                         if (pos == 0)
274                         {
275                                 DEBUG(0, ("mangle: unable to mangle file name!\n"));
276                                 goto done;
277                         }
278                         strncpy_w(temp, umpref, pos);
279                         temp[pos] = 0;
280                         strlower_w(temp);
281
282                         /* convert any invalid char into '_' */
283                         strvalid(temp);
284                         ud83_len = ucs2_to_dos(prefix, temp, sizeof(prefix));
285                         if (!ud83_len) goto done;
286                 }
287                 while (ud83_len > 8 - MANGLE_SUFFIX_SIZE);
288
289                 slprintf(keylock, sizeof(keylock)-1, "%s%s", COUNTER_PREFIX, prefix);
290                 klock.dptr = keylock;
291                 klock.dsize = strlen(keylock) + 1;
292
293                 c = 0;
294                 data.dptr = (char *)&c;
295                 data.dsize = sizeof(uint32);
296                 /* try to insert a new counter prefix, if it exist the call will
297                    fail (correct) otherwise it will create a new entry with counter set
298                    to 0
299                  */
300                 if(tdb_store(mangle_tdb, klock, data, TDB_INSERT) != TDB_SUCCESS)
301                 {
302                         if (tdb_error(mangle_tdb) != TDB_ERR_EXISTS)
303                         {
304                                 DEBUG(0, ("mangle: database store error: %s\n",
305                                         tdb_errorstr(mangle_tdb)));
306                                 goto done;
307                         }
308                 }
309
310                 /* lock the mangle counter for this prefix */           
311                 if (tdb_chainlock(mangle_tdb, klock))
312                 {
313                         DEBUG(0,("mangle: failed to lock database\n!"));
314                         goto done;
315                 }
316                 tclock = True;
317
318                 data = tdb_fetch(mangle_tdb, klock);
319                 if (!data.dptr)
320                 {
321                         DEBUG(0, ("mangle: database retrieval error: %s\n",
322                                         tdb_errorstr(mangle_tdb)));
323                         goto done;
324                 }
325                 c = *((uint32 *)data.dptr);
326                 c++;
327                 
328                 if (c > MANGLE_COUNTER_MAX)
329                 {
330                         DEBUG(0, ("mangle: error, counter overflow!\n"));
331                         goto done;
332                 }
333                         
334                 temp[pos] = UCS2_CHAR('~');
335                 temp[pos+1] = 0;
336                 snprintf(suffix, 7, "%.6d", c);
337                 strncat_wa(temp, &suffix[7 - MANGLE_SUFFIX_SIZE], MANGLE_SUFFIX_SIZE);
338
339                 ud83_len = ucs2_to_dos(mufname, temp, sizeof(mufname));
340                 if (!ud83_len) goto done;
341                 if (ud83_len > 8)
342                 {
343                         DEBUG(0, ("mangle: darn, logic error aborting!\n"));
344                         goto done;
345                 }
346                         
347                 /* store the long entry with mangled key */
348                 slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
349                 key.dptr = keystr;
350                 key.dsize = strlen (keystr) + 1;
351                 data.dsize = (strlen_w(umpref) + 1) * sizeof (smb_ucs2_t);
352                 data.dptr = (void *)umpref;
353
354                 if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
355                 {
356                         DEBUG(0, ("mangle: database store error: %s\n",
357                                         tdb_errorstr(mangle_tdb)));
358                         goto done;
359                 }
360
361                 /* store the mangled entry with long key*/
362                 pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
363                 slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
364                 key.dptr = keystr;
365                 key.dsize = strlen (keystr) + 1;
366                 data.dsize = strlen(mufname) + 1;
367                 data.dptr = mufname;
368                 if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
369                 {
370                         DEBUG(0, ("mangle: database store failed: %s\n",
371                                         tdb_errorstr(mangle_tdb)));
372
373                         /* try to delete the mangled key entry to avoid later inconsistency */
374                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
375                         key.dptr = keystr;
376                         key.dsize = strlen (keystr) + 1;
377                         if (!tdb_delete(mangle_tdb, key))
378                         {
379                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
380                         }
381                         goto done;
382                 }
383
384                 p = strdup_w(temp);
385                 if (!p)
386                 {
387                         DEBUG(0,("mangle: out of memory!\n"));
388                         goto done;
389                 }
390                 
391                 data.dptr = (char *)&c;
392                 data.dsize = sizeof(uint32);
393                 /* store the counter */
394                 if(tdb_store(mangle_tdb, klock, data, TDB_REPLACE) != TDB_SUCCESS)
395                 {
396                         DEBUG(0, ("mangle: database store failed: %s\n",
397                                         tdb_errorstr(mangle_tdb)));
398                         /* try to delete the mangled and long key entry to avoid later inconsistency */
399                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
400                         key.dptr = keystr;
401                         key.dsize = strlen (keystr) + 1;
402                         if (!tdb_delete(mangle_tdb, key))
403                         {
404                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
405                         }
406                         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
407                         key.dptr = keystr;
408                         key.dsize = strlen (keystr) + 1;
409                         if (!tdb_delete(mangle_tdb, key))
410                         {
411                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
412                         }
413                         goto done;
414                 }
415
416                 tclock = False;
417                 tdb_chainunlock(mangle_tdb, klock);
418         }
419         else /* FOUND */
420         {
421                 p = acnv_dosu2(data.dptr);
422                 if (!p)
423                 {
424                         DEBUG(0,("mangle: out of memory!\n"));
425                         goto done;
426                 }
427         }
428                 
429         if (ext)
430         {
431                 pref_len = strlen_w(p);
432                 ext_len = strlen_w(ext);
433                 mangled = (smb_ucs2_t *)malloc((pref_len + ext_len + 2)*sizeof(smb_ucs2_t));
434                 if (!mangled)
435                 {
436                         DEBUG(0,("mangle: out of memory!\n"));
437                         goto done;
438                 }
439                 strncpy_w (mangled, p, pref_len);
440                 mangled[pref_len] = UCS2_CHAR('.');
441                 mangled[pref_len + 1] = 0;
442                 strncat_w (mangled, ext, ext_len);
443         }
444         else
445         {
446                 mangled = strdup_w(p);
447                 if (!mangled)
448                 {
449                         DEBUG(0,("mangle: out of memory!\n"));
450                         goto done;
451                 }
452         }
453
454         /* mangled name are returned in upper or lower case depending on
455            case_default value */
456         strnorm_w(mangled);
457
458 done:
459         if (tclock) tdb_chainunlock(mangle_tdb, klock);
460         SAFE_FREE(p);
461         SAFE_FREE(umpref);
462         SAFE_FREE(ext);
463
464         return mangled;
465 }
466
467
468 /* non unicode compatibility functions */
469
470 char *dos_mangle(const char *dos_unmangled)
471 {
472         smb_ucs2_t *in, *out;
473         char *dos_mangled;
474
475         if (!dos_unmangled || !*dos_unmangled) return NULL;
476
477         in = acnv_dosu2(dos_unmangled);
478         if (!in)
479         {
480                 DEBUG(0,("dos_mangle: out of memory!\n"));
481                 return NULL;
482         }
483
484         out = mangle(in);
485         if (!out)
486         {
487                 SAFE_FREE(in);
488                 return NULL;
489         }
490
491         dos_mangled = acnv_u2dos(out);
492         if (!dos_mangled)
493         {
494                 DEBUG(0,("dos_mangle: out of memory!\n"));
495                 goto done;
496         }
497
498 done:
499         SAFE_FREE(in);
500         SAFE_FREE(out);
501         return dos_mangled;
502 }
503
504 char *dos_unmangle(const char *dos_mangled)
505 {
506         smb_ucs2_t *in, *out;
507         char *dos_unmangled;
508
509         if (!dos_mangled || !*dos_mangled) return NULL;
510
511         in = acnv_dosu2(dos_mangled);
512         if (!in)
513         {
514                 DEBUG(0,("dos_unmangle: out of memory!\n"));
515                 return NULL;
516         }
517
518         out = mangle(in);
519         if (!out)
520         {
521                 SAFE_FREE(in);
522                 return NULL;
523         }
524
525         dos_unmangled = acnv_u2dos(out);
526         if (!dos_unmangled)
527         {
528                 DEBUG(0,("dos_unmangle: out of memory!\n"));
529                 goto done;
530         }
531
532 done:
533         SAFE_FREE(in);
534         SAFE_FREE(out);
535         return dos_unmangled;
536 }
537
538 BOOL is_8_3(const char *fname, BOOL check_case)
539 {
540         const char *f;
541         smb_ucs2_t *ucs2name;
542         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
543
544         if (!fname || !*fname) return False;
545         if ((f = strrchr(fname, '/')) == NULL) f = fname;
546         else f++;
547
548         DEBUG(10,("is_8_3: testing [%s]\n", f));
549
550         if (strlen(f) > 12) return False;
551         
552         ucs2name = acnv_uxu2(f);
553         if (!ucs2name)
554         {
555                 DEBUG(0,("is_8_3: out of memory!\n"));
556                 goto done;
557         }
558
559         ret = is_8_3_w(ucs2name);
560
561 done:
562         SAFE_FREE(ucs2name);
563
564         DEBUG(10,("is_8_3: returning -> %s\n", NT_STATUS_IS_OK(ret)?"True":"False"));
565
566         if (NT_STATUS_IS_ERR(ret)) return False;
567         else return True;
568 }
569
570 NTSTATUS is_8_3_w(const smb_ucs2_t *fname)
571 {
572         smb_ucs2_t *pref = 0, *ext = 0;
573         size_t plen;
574         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
575
576         if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
577
578         DEBUG(10,("is_8_3_w: testing\n")); /* [%s]\n", fname)); */
579
580         if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL;
581         
582         if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
583                 return NT_STATUS_OK;
584
585         if (NT_STATUS_IS_ERR(is_valid_name(fname))) goto done;
586
587         if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext))) goto done;
588         plen = strlen_w(pref);
589
590         if (strchr_wa(pref, '.')) goto done;
591         if (plen < 1 || plen > 8) goto done;
592         if (ext) if (strlen_w(ext) > 3) goto done;
593
594         ret = NT_STATUS_OK;
595
596 done:
597         SAFE_FREE(pref);
598         SAFE_FREE(ext);
599         return ret;
600 }
601
602 NTSTATUS has_valid_chars(const smb_ucs2_t *s)
603 {
604         NTSTATUS ret = NT_STATUS_OK;
605
606         if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
607
608         DEBUG(10,("has_valid_chars: testing\n")); /* [%s]\n", s)); */
609         
610         /* CHECK: this should not be necessary if the ms wild chars
611            are not valid in valid.dat  --- simo */
612         if (ms_has_wild_w(s)) return NT_STATUS_UNSUCCESSFUL;
613
614         while (*s) {
615                 if(!isvalid83_w(*s)) return NT_STATUS_UNSUCCESSFUL;
616                 s++;
617         }
618
619         return ret;
620 }
621
622 NTSTATUS is_valid_name(const smb_ucs2_t *fname)
623 {
624         smb_ucs2_t *str, *p;
625         NTSTATUS ret = NT_STATUS_OK;
626
627         if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
628
629         DEBUG(10,("is_valid_name: testing\n")); /* [%s]\n", s)); */
630
631         if (*fname == UCS2_CHAR('.')) return NT_STATUS_UNSUCCESSFUL;
632         
633         ret = has_valid_chars(fname);
634         if (NT_STATUS_IS_ERR(ret)) return ret;
635
636         str = strdup_w(fname);
637         p = strchr_w(str, UCS2_CHAR('.'));
638         if (p) *p = 0;
639         strupper_w(str);
640         p = &(str[1]);
641
642         switch(str[0])
643         {
644         case UCS2_CHAR('A'):
645                 if(strcmp_wa(p, "UX") == 0)
646                         ret = NT_STATUS_UNSUCCESSFUL;
647                 break;
648         case UCS2_CHAR('C'):
649                 if((strcmp_wa(p, "LOCK$") == 0)
650                 || (strcmp_wa(p, "ON") == 0)
651                 || (strcmp_wa(p, "OM1") == 0)
652                 || (strcmp_wa(p, "OM2") == 0)
653                 || (strcmp_wa(p, "OM3") == 0)
654                 || (strcmp_wa(p, "OM4") == 0)
655                 )
656                         ret = NT_STATUS_UNSUCCESSFUL;
657                 break;
658         case UCS2_CHAR('L'):
659                 if((strcmp_wa(p, "PT1") == 0)
660                 || (strcmp_wa(p, "PT2") == 0)
661                 || (strcmp_wa(p, "PT3") == 0)
662                 )
663                         ret = NT_STATUS_UNSUCCESSFUL;
664                 break;
665         case UCS2_CHAR('N'):
666                 if(strcmp_wa(p, "UL") == 0)
667                         ret = NT_STATUS_UNSUCCESSFUL;
668                 break;
669         case UCS2_CHAR('P'):
670                 if(strcmp_wa(p, "RN") == 0)
671                         ret = NT_STATUS_UNSUCCESSFUL;
672                 break;
673         default:
674                 break;
675         }
676
677         SAFE_FREE(str);
678         return ret;
679 }
680
681 BOOL is_mangled(const char *s)
682 {
683         smb_ucs2_t *u2, *res;
684         BOOL ret = False;
685         
686         DEBUG(10,("is_mangled: testing [%s]\n", s));
687         
688         if (!s || !*s) return False;
689         if ((strlen(s) > 12) || (!strchr(s, '~'))) return False;
690         
691         u2 = acnv_dosu2(s);
692         if (!u2)
693         {
694                 DEBUG(0,("is_mangled: out of memory!\n"));
695                 return ret;
696         }
697
698         res = unmangle(u2);
699         if (res) ret = True;
700         SAFE_FREE(res);
701         SAFE_FREE(u2);
702         DEBUG(10,("is_mangled: returning  [%s]\n", ret?"True":"False"));
703         return ret;
704 }
705
706 NTSTATUS is_mangled_w(const smb_ucs2_t *s)
707 {
708         smb_ucs2_t *res;
709         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
710         
711         res = unmangle(s);
712         if (res) ret = NT_STATUS_OK;
713         SAFE_FREE(res);
714         return ret;
715 }
716
717 NTSTATUS path_has_mangled(const smb_ucs2_t *s)
718 {
719         smb_ucs2_t *p, *f, *b;
720         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
721
722         if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
723
724         p = strdup_w(s);
725         if (!p) return NT_STATUS_NO_MEMORY;
726         trim_string_wa(p, "/", "/");
727         f = b = p;
728         while (b) {
729                 b = strchr_w(f, UCS2_CHAR('/'));
730                 if (b) *b = 0;
731                 if (NT_STATUS_IS_OK(is_mangled_w(f))) {
732                         ret = NT_STATUS_OK;
733                         goto done;
734                 }
735                 f = b + 1;
736         }
737 done:
738         SAFE_FREE(p);
739         return ret;
740 }
741
742 /* backward compatibility functions */
743
744 void reset_mangled_cache(void)
745 {
746         DEBUG(10,("reset_mangled_cache: compatibility function, remove me!\n"));
747 }
748
749 BOOL check_mangled_cache(char *s)
750 {
751         smb_ucs2_t *u2, *res;
752         BOOL ret = False;
753
754         DEBUG(10,("check_mangled_cache: I'm so ugly, please remove me!\n"));
755         DEBUG(10,("check_mangled_cache: testing -> [%s]\n", s));
756
757         if (!s || !*s) return False;
758
759         u2 = acnv_dosu2(s);
760         if (!u2)
761         {
762                 DEBUG(0,("check_mangled_cache: out of memory!\n"));
763                 return ret;
764         }
765
766         res = unmangle(u2);
767         if (res)
768         {
769                 
770                 ucs2_to_dos (s, res, PSTRING_LEN);
771                 /* We MUST change this brainded interface,
772                    we do not know how many chars will be used
773                    in dos so i guess they will be no more than
774                    double the size of the unicode string
775                           ---simo */
776                 DEBUG(10,("check_mangled_cache: returning -> [%s]\n", s));
777                 ret = True;
778         }
779         SAFE_FREE(res);
780         SAFE_FREE(u2);
781         DEBUG(10,("check_mangled_cache: returning -> %s\n", ret?"True":"False"));
782         return ret;
783 }
784
785 void mangle_name_83(char *s)
786 {
787         smb_ucs2_t *u2, *res;
788
789         DEBUG(10,("mangle_name_83: I'm so ugly, please remove me!\n"));
790         DEBUG(10,("mangle_name_83: testing -> [%s]\n", s));
791
792         if (!s || !*s) return;
793         
794         u2 = acnv_dosu2(s);
795         if (!u2)
796         {
797                 DEBUG(0,("mangle_name_83: out of memory!\n"));
798                 return;
799         }
800
801         res = mangle(u2);
802         if (res) ucs2_to_dos (s, res, 13); /* ugly, but must be done this way */
803         DEBUG(10,("mangle_name_83: returning -> [%s]\n", s));
804         SAFE_FREE(res);
805         SAFE_FREE(u2);
806 }
807
808 BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
809 {
810         DEBUG(10,("name_map_mangle: I'm so ugly, please remove me!\n"));
811
812         if (!need83) return True;
813         /* if (is_8_3(OutName, True)) return True; */
814         /* Warning: we should check for invalid chars in file name and mangle
815            if invalid chars found --simo*/
816
817         mangle_name_83(OutName);
818         return True;
819 }
820
821
822
823 #if 0 /* TEST_MANGLE_CODE */
824
825 #define LONG            "this_is_a_long_file_name"
826 #define LONGM           "this_~01"
827 #define SHORT           "short"
828 #define SHORTM          "short~01"
829 #define EXT1            "ex1"
830 #define EXT2            "e2"
831 #define EXT3            "3"
832 #define EXTFAIL         "longext"
833 #define EXTNULL         ""
834
835 static void unmangle_test (char *name, char *ext)
836 {
837         smb_ucs2_t ucs2_name[2048];
838         smb_ucs2_t *retstr;
839         pstring unix_name;      
840
841         push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
842         if (ext)
843         {
844                 strncat_wa(ucs2_name, ".", 1);
845                 strncat_wa(ucs2_name, ext, strlen(ext) + 1);
846         }
847         retstr = unmangle(ucs2_name);
848         if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
849         else unix_name[0] = 0;
850         if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
851         else printf ("[%s] ---> [%s]\n", name, unix_name);
852         SAFE_FREE(retstr);
853 }
854
855 static void mangle_test (char *name, char *ext)
856 {
857         smb_ucs2_t ucs2_name[2048];
858         smb_ucs2_t *retstr;
859         pstring unix_name;      
860
861         push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
862         if (ext)
863         {
864                 strncat_wa(ucs2_name, ".", 1);
865                 strncat_wa(ucs2_name, ext, strlen(ext) + 1);
866         }
867         retstr = mangle(ucs2_name);
868         if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
869         else unix_name[0] = 0;
870         if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
871         else printf ("[%s] ---> [%s]\n", name, unix_name);
872         SAFE_FREE(retstr);
873 }
874
875 void mangle_test_code(void)
876 {
877         init_mangle_tdb();
878
879         /* unmangle every */
880         printf("Unmangle test 1:\n");
881
882         unmangle_test (LONG, NULL);
883         unmangle_test (LONG, EXT1);
884         unmangle_test (LONG, EXT2);
885         unmangle_test (LONG, EXT3);
886         unmangle_test (LONG, EXTFAIL);
887         unmangle_test (LONG, EXTNULL);
888
889         unmangle_test (LONGM, NULL);
890         unmangle_test (LONGM, EXT1);
891         unmangle_test (LONGM, EXT2);
892         unmangle_test (LONGM, EXT3);
893         unmangle_test (LONGM, EXTFAIL);
894         unmangle_test (LONGM, EXTNULL);
895
896         unmangle_test (SHORT, NULL);
897         unmangle_test (SHORT, EXT1);
898         unmangle_test (SHORT, EXT2);
899         unmangle_test (SHORT, EXT3);
900         unmangle_test (SHORT, EXTFAIL);
901         unmangle_test (SHORT, EXTNULL);
902
903         unmangle_test (SHORTM, NULL);
904         unmangle_test (SHORTM, EXT1);
905         unmangle_test (SHORTM, EXT2);
906         unmangle_test (SHORTM, EXT3);
907         unmangle_test (SHORTM, EXTFAIL);
908         unmangle_test (SHORTM, EXTNULL);
909
910         /* mangle every */
911         printf("Mangle test\n");
912
913         mangle_test (LONG, NULL);
914         mangle_test (LONG, EXT1);
915         mangle_test (LONG, EXT2);
916         mangle_test (LONG, EXT3);
917         mangle_test (LONG, EXTFAIL);
918         mangle_test (LONG, EXTNULL);
919
920         mangle_test (LONGM, NULL);
921         mangle_test (LONGM, EXT1);
922         mangle_test (LONGM, EXT2);
923         mangle_test (LONGM, EXT3);
924         mangle_test (LONGM, EXTFAIL);
925         mangle_test (LONGM, EXTNULL);
926
927         mangle_test (SHORT, NULL);
928         mangle_test (SHORT, EXT1);
929         mangle_test (SHORT, EXT2);
930         mangle_test (SHORT, EXT3);
931         mangle_test (SHORT, EXTFAIL);
932         mangle_test (SHORT, EXTNULL);
933
934         mangle_test (SHORTM, NULL);
935         mangle_test (SHORTM, EXT1);
936         mangle_test (SHORTM, EXT2);
937         mangle_test (SHORTM, EXT3);
938         mangle_test (SHORTM, EXTFAIL);
939         mangle_test (SHORTM, EXTNULL);
940
941         /* unmangle again every */
942         printf("Unmangle test 2:\n");
943
944         unmangle_test (LONG, NULL);
945         unmangle_test (LONG, EXT1);
946         unmangle_test (LONG, EXT2);
947         unmangle_test (LONG, EXT3);
948         unmangle_test (LONG, EXTFAIL);
949         unmangle_test (LONG, EXTNULL);
950
951         unmangle_test (LONGM, NULL);
952         unmangle_test (LONGM, EXT1);
953         unmangle_test (LONGM, EXT2);
954         unmangle_test (LONGM, EXT3);
955         unmangle_test (LONGM, EXTFAIL);
956         unmangle_test (LONGM, EXTNULL);
957
958         unmangle_test (SHORT, NULL);
959         unmangle_test (SHORT, EXT1);
960         unmangle_test (SHORT, EXT2);
961         unmangle_test (SHORT, EXT3);
962         unmangle_test (SHORT, EXTFAIL);
963         unmangle_test (SHORT, EXTNULL);
964
965         unmangle_test (SHORTM, NULL);
966         unmangle_test (SHORTM, EXT1);
967         unmangle_test (SHORTM, EXT2);
968         unmangle_test (SHORTM, EXT3);
969         unmangle_test (SHORTM, EXTFAIL);
970         unmangle_test (SHORTM, EXTNULL);
971 }
972
973 #endif /* TEST_MANGLE_CODE */