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