home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Wtestowe / Clico / UNIX / SAMBA / SOURCE / SAMBA.TAR / samba-1.9.17 / source / mangle.c < prev    next >
C/C++ Source or Header  |  1997-05-08  |  18KB  |  661 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Name mangling
  5.    Copyright (C) Andrew Tridgell 1992-1997
  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. #include "includes.h"
  23.  
  24. extern int DEBUGLEVEL;
  25. extern int case_default;
  26. extern BOOL case_mangle;
  27.  
  28. /****************************************************************************
  29. provide a checksum on a string
  30. ****************************************************************************/
  31. int str_checksum(char *s)
  32. {
  33.   int res = 0;
  34.   int c;
  35.   int i=0;
  36.   while (*s)
  37.     {
  38.       c = *s;
  39.       res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
  40.       s++; i++;
  41.     }
  42.   return(res);
  43. }
  44.  
  45. /****************************************************************************
  46. return True if a name is a special msdos reserved name
  47. ****************************************************************************/
  48. static BOOL is_reserved_msdos(char *fname)
  49. {
  50.   char upperFname[13];
  51.   char *p;
  52.  
  53.   StrnCpy (upperFname, fname, 12);
  54.  
  55.   /* lpt1.txt and con.txt etc are also illegal */
  56.   p=strchr(upperFname,'.');
  57.   if (p)
  58.    *p='\0';
  59.   strupper (upperFname);
  60.   if ((strcmp(upperFname,"CLOCK$") == 0) ||
  61.     (strcmp(upperFname,"CON") == 0) ||
  62.     (strcmp(upperFname,"AUX") == 0) ||
  63.     (strcmp(upperFname,"COM1") == 0) ||
  64.     (strcmp(upperFname,"COM2") == 0) ||
  65.     (strcmp(upperFname,"COM3") == 0) ||
  66.     (strcmp(upperFname,"COM4") == 0) ||
  67.     (strcmp(upperFname,"LPT1") == 0) ||
  68.     (strcmp(upperFname,"LPT2") == 0) ||
  69.     (strcmp(upperFname,"LPT3") == 0) ||
  70.     (strcmp(upperFname,"NUL") == 0) ||
  71.     (strcmp(upperFname,"PRN") == 0))
  72.       return (True) ;
  73.  
  74.   return (False);
  75. }
  76.  
  77.  
  78.  
  79. /****************************************************************************
  80. return True if a name is in 8.3 dos format
  81. ****************************************************************************/
  82. BOOL is_8_3(char *fname, BOOL check_case)
  83. {
  84.   int len;
  85.   char *dot_pos;
  86.   char *slash_pos = strrchr(fname,'/');
  87.   int l;
  88.  
  89.   if (slash_pos) fname = slash_pos+1;
  90.   len = strlen(fname);
  91.  
  92.   DEBUG(5,("checking %s for 8.3\n",fname));
  93.  
  94.   if (check_case && case_mangle)
  95.     switch (case_default)
  96.       {
  97.       case CASE_LOWER:
  98.     if (strhasupper(fname)) return(False);
  99.     break;
  100.       case CASE_UPPER:
  101.     if (strhaslower(fname)) return(False);
  102.     break;
  103.       }
  104.  
  105.   /* can't be longer than 12 chars */
  106.   if (len == 0 || len > 12)
  107.     return(False);
  108.  
  109.   /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
  110.   if (is_reserved_msdos(fname))
  111.     return(False);
  112.  
  113.   /* can't contain invalid dos chars */
  114.   /* Windows use the ANSI charset.
  115.      But filenames are translated in the PC charset.
  116.      This Translation may be more or less relaxed depending
  117.      the Windows application. */
  118.  
  119.   /* %%% A nice improvment to name mangling would be to translate
  120.      filename to ANSI charset on the smb server host */
  121.  
  122.   dot_pos = strchr(fname,'.');
  123.  
  124.   {
  125.     char *p = fname;
  126. #ifdef KANJI
  127.     dot_pos = 0;
  128.     while (*p)
  129.       {
  130.       if (is_shift_jis (*p)) {
  131.           p += 2;
  132.       } else if (is_kana (*p)) {
  133.           p ++;
  134.       } else {
  135.           if (*p == '.' && !dot_pos)
  136.           dot_pos = (char *) p;
  137.           if (!isdoschar(*p))
  138.           return(False);
  139.           p++;
  140.       }
  141.       }      
  142. #else
  143.     while (*p)
  144.       {
  145.     if (!isdoschar(*p))
  146.       return(False);
  147.     p++;
  148.       }      
  149. #endif /* KANJI */
  150.   }
  151.  
  152.   /* no dot and less than 9 means OK */
  153.   if (!dot_pos)
  154.     return(len <= 8);
  155.     
  156.   l = PTR_DIFF(dot_pos,fname);
  157.  
  158.   /* base must be at least 1 char except special cases . and .. */
  159.   if (l == 0)
  160.     return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0);
  161.  
  162.   /* base can't be greater than 8 */
  163.   if (l > 8)
  164.     return(False);
  165.  
  166.   if (lp_strip_dot() && 
  167.       len - l == 1 &&
  168.       !strchr(dot_pos+1,'.'))
  169.     {
  170.       *dot_pos = 0;
  171.       return(True);
  172.     }
  173.  
  174.   /* extension must be between 1 and 3 */
  175.   if ( (len - l < 2 ) || (len - l > 4) )
  176.     return(False);
  177.  
  178.   /* extension can't have a dot */
  179.   if (strchr(dot_pos+1,'.'))
  180.     return(False);
  181.  
  182.   /* must be in 8.3 format */
  183.   return(True);
  184. }
  185.  
  186.  
  187.  
  188. /*
  189. keep a stack of name mangling results - just
  190. so file moves and copies have a chance of working
  191. */
  192. fstring *mangled_stack = NULL;
  193. int mangled_stack_size = 0;
  194. int mangled_stack_len = 0;
  195.  
  196. /****************************************************************************
  197. create the mangled stack
  198. ****************************************************************************/
  199. void create_mangled_stack(int size)
  200. {
  201.   if (mangled_stack)
  202.     {
  203.       free(mangled_stack);
  204.       mangled_stack_size = 0;
  205.       mangled_stack_len = 0;
  206.     }
  207.   if (size > 0)
  208.     mangled_stack = (fstring *)malloc(sizeof(fstring)*size);
  209.   if (mangled_stack) mangled_stack_size = size;
  210. }
  211.  
  212. /****************************************************************************
  213. push a mangled name onto the stack
  214. ****************************************************************************/
  215. static void push_mangled_name(char *s)
  216. {
  217.   int i;
  218.   char *p;
  219.  
  220.   if (!mangled_stack)
  221.     return;
  222.  
  223.   for (i=0;i<mangled_stack_len;i++)
  224.     if (strcmp(s,mangled_stack[i]) == 0)
  225.       {
  226.     array_promote(mangled_stack[0],sizeof(fstring),i);    
  227.     return;
  228.       }
  229.  
  230.   memmove(mangled_stack[1],mangled_stack[0],
  231.       sizeof(fstring)*MIN(mangled_stack_len,mangled_stack_size-1));
  232.   strcpy(mangled_stack[0],s);
  233.   p = strrchr(mangled_stack[0],'.');
  234.   if (p && (!strhasupper(p+1)) && (strlen(p+1) < 4))
  235.     *p = 0;
  236.   mangled_stack_len = MIN(mangled_stack_size,mangled_stack_len+1);
  237. }
  238.  
  239. /****************************************************************************
  240. check for a name on the mangled name stack
  241. ****************************************************************************/
  242. BOOL check_mangled_stack(char *s)
  243. {
  244.   int i;
  245.   pstring tmpname;
  246.   char extension[5];
  247.   char *p = strrchr(s,'.');
  248.   BOOL check_extension = False;
  249.  
  250.   extension[0] = 0;
  251.  
  252.   if (!mangled_stack) return(False);
  253.  
  254.   if (p)
  255.     {
  256.       check_extension = True;
  257.       StrnCpy(extension,p,4);
  258.       strlower(extension); /* XXXXXXX */
  259.     }
  260.  
  261.   for (i=0;i<mangled_stack_len;i++)
  262.     {
  263.       strcpy(tmpname,mangled_stack[i]);
  264.       mangle_name_83(tmpname);
  265.       if (strequal(tmpname,s))
  266.     {
  267.       strcpy(s,mangled_stack[i]);
  268.       break;
  269.     }
  270.       if (check_extension && !strchr(mangled_stack[i],'.'))
  271.     {
  272.       strcpy(tmpname,mangled_stack[i]);
  273.       strcat(tmpname,extension);
  274.       mangle_name_83(tmpname);
  275.       if (strequal(tmpname,s))
  276.         {
  277.           strcpy(s,mangled_stack[i]);
  278.           strcat(s,extension);
  279.           break;
  280.         }      
  281.     }
  282.     }
  283.  
  284.   if (i < mangled_stack_len)
  285.     {
  286.       DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i]));
  287.       array_promote(mangled_stack[0],sizeof(fstring),i);
  288.       return(True);      
  289.     }
  290.  
  291.   return(False);
  292. }    
  293.  
  294. static char *map_filename(char *s, /* This is null terminated */
  295.               char *pattern, /* This isn't. */
  296.               int len) /* This is the length of pattern. */
  297. {
  298.   static pstring matching_bit;  /* The bit of the string which matches */
  299.                                 /* a * in pattern if indeed there is a * */
  300.   char *sp;                     /* Pointer into s. */
  301.   char *pp;                     /* Pointer into p. */
  302.   char *match_start;            /* Where the matching bit starts. */
  303.   pstring pat;
  304.  
  305.   StrnCpy(pat, pattern, len);   /* Get pattern into a proper string! */
  306.   strcpy(matching_bit,"");      /* Match but no star gets this. */
  307.   pp = pat;                     /* Initialise the pointers. */
  308.   sp = s;
  309.   if ((len == 1) && (*pattern == '*')) {
  310.     return NULL;                /* Impossible, too ambiguous for */
  311.                                 /* words! */
  312.   }
  313.  
  314.   while ((*sp)                  /* Not the end of the string. */
  315.          && (*pp)               /* Not the end of the pattern. */
  316.          && (*sp == *pp)        /* The two match. */
  317.          && (*pp != '*')) {     /* No wildcard. */
  318.     sp++;                       /* Keep looking. */
  319.     pp++;
  320.   }
  321.   if (!*sp && !*pp)             /* End of pattern. */
  322.     return matching_bit;        /* Simple match.  Return empty string. */
  323.   if (*pp == '*') {
  324.     pp++;                       /* Always interrested in the chacter */
  325.                                 /* after the '*' */
  326.     if (!*pp) {                 /* It is at the end of the pattern. */
  327.       StrnCpy(matching_bit, s, sp-s);
  328.       return matching_bit;
  329.     } else {
  330.       /* The next character in pattern must match a character further */
  331.       /* along s than sp so look for that character. */
  332.       match_start = sp;
  333.       while ((*sp)              /* Not the end of s. */
  334.              && (*sp != *pp))   /* Not the same  */
  335.         sp++;                   /* Keep looking. */
  336.       if (!*sp) {               /* Got to the end without a match. */
  337.         return NULL;
  338.       } else {                  /* Still hope for a match. */
  339.         /* Now sp should point to a matching character. */
  340.         StrnCpy(matching_bit, match_start, sp-match_start);
  341.         /* Back to needing a stright match again. */
  342.         while ((*sp)            /* Not the end of the string. */
  343.                && (*pp)         /* Not the end of the pattern. */
  344.                && (*sp == *pp)) { /* The two match. */
  345.           sp++;                 /* Keep looking. */
  346.           pp++;
  347.         }
  348.         if (!*sp && !*pp)       /* Both at end so it matched */
  349.           return matching_bit;
  350.         else
  351.           return NULL;
  352.       }
  353.     }
  354.   }
  355.   return NULL;                  /* No match. */
  356. }
  357.  
  358.  
  359. /* this is the magic char used for mangling */
  360. char magic_char = '~';
  361.  
  362.  
  363. /****************************************************************************
  364. determine whther is name could be a mangled name
  365. ****************************************************************************/
  366. BOOL is_mangled(char *s)
  367. {
  368.   char *m = strchr(s,magic_char);
  369.   if (!m) return(False);
  370.  
  371.   /* we use two base 36 chars efore the extension */
  372.   if (m[1] == '.' || m[1] == 0 ||
  373.       m[2] == '.' || m[2] == 0 ||
  374.       (m[3] != '.' && m[3] != 0))
  375.     return(is_mangled(m+1));
  376.  
  377.   /* it could be */
  378.   return(True);
  379. }
  380.  
  381.  
  382.  
  383. /****************************************************************************
  384. return a base 36 character. v must be from 0 to 35.
  385. ****************************************************************************/
  386. static char base36(unsigned int v)
  387. {
  388.   static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  389.   return basechars[v % 36];
  390. }
  391.  
  392.  
  393. static void do_fwd_mangled_map(char *s, char *MangledMap)
  394. {
  395.   /* MangledMap is a series of name pairs in () separated by spaces.
  396.    * If s matches the first of the pair then the name given is the
  397.    * second of the pair.  A * means any number of any character and if
  398.    * present in the second of the pair as well as the first the
  399.    * matching part of the first string takes the place of the * in the
  400.    * second.
  401.    *
  402.    * I wanted this so that we could have RCS files which can be used
  403.    * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
  404.    * converts the UNIX RCS file subdirectory to lowercase thus
  405.    * preventing mangling.
  406.    */
  407.   char *start=MangledMap;       /* Use this to search for mappings. */
  408.   char *end;                    /* Used to find the end of strings. */
  409.   char *match_string;
  410.   pstring new_string;           /* Make up the result here. */
  411.   char *np;                     /* Points into new_string. */
  412.  
  413.   DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap));
  414.   while (*start) {
  415.     while ((*start) && (*start != '('))
  416.       start++;
  417.     start++;                    /* Skip the ( */
  418.     if (!*start)
  419.       continue;                 /* Always check for the end. */
  420.     end = start;                /* Search for the ' ' or a ')' */
  421.     DEBUG(5,("Start of first in pair '%s'\n", start));
  422.     while ((*end) && !((*end == ' ') || (*end == ')')))
  423.       end++;
  424.     if (!*end) {
  425.       start = end;
  426.       continue;                 /* Always check for the end. */
  427.     }
  428.     DEBUG(5,("End of first in pair '%s'\n", end));
  429.     if ((match_string = map_filename(s, start, end-start))) {
  430.       DEBUG(5,("Found a match\n"));
  431.       /* Found a match. */
  432.       start = end+1;            /* Point to start of what it is to become. */
  433.       DEBUG(5,("Start of second in pair '%s'\n", start));
  434.       end = start;
  435.       np = new_string;
  436.       while ((*end)             /* Not the end of string. */
  437.              && (*end != ')')   /* Not the end of the pattern. */
  438.              && (*end != '*'))  /* Not a wildcard. */
  439.         *np++ = *end++;
  440.       if (!*end) {
  441.         start = end;
  442.         continue;               /* Always check for the end. */
  443.       }
  444.       if (*end == '*') {
  445.         strcpy(np, match_string);
  446.         np += strlen(match_string);
  447.         end++;                  /* Skip the '*' */
  448.         while ((*end)             /* Not the end of string. */
  449.                && (*end != ')')   /* Not the end of the pattern. */
  450.                && (*end != '*'))  /* Not a wildcard. */
  451.           *np++ = *end++;
  452.       }
  453.       if (!*end) {
  454.         start = end;
  455.         continue;               /* Always check for the end. */
  456.       }
  457.       *np++ = '\0';             /* NULL terminate it. */
  458.       DEBUG(5,("End of second in pair '%s'\n", end));
  459.       strcpy(s, new_string);    /* Substitute with the new name. */
  460.       DEBUG(5,("s is now '%s'\n", s));
  461.     }
  462.     start = end;              /* Skip a bit which cannot be wanted */
  463.     /* anymore. */
  464.     start++;
  465.   }
  466. }
  467.  
  468. /****************************************************************************
  469. do the actual mangling to 8.3 format
  470. ****************************************************************************/
  471. void mangle_name_83(char *s)
  472. {
  473.   int csum = str_checksum(s);
  474.   char *p;
  475.   char extension[4];
  476.   char base[9];
  477.   int baselen = 0;
  478.   int extlen = 0;
  479.  
  480.   extension[0]=0;
  481.   base[0]=0;
  482.  
  483.   p = strrchr(s,'.');  
  484.   if (p && (strlen(p+1)<4) )
  485.     {
  486.       BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
  487.       if (all_normal && p[1] != 0)
  488.     {
  489.       *p = 0;
  490.       csum = str_checksum(s);
  491.       *p = '.';
  492.     }
  493.     }
  494.       
  495.  
  496.   strupper(s);
  497.  
  498.   DEBUG(5,("Mangling name %s to ",s));
  499.  
  500.   if (p)
  501.     {
  502.       if (p == s)
  503.     strcpy(extension,"___");
  504.       else
  505.     {
  506.       *p++ = 0;
  507.       while (*p && extlen < 3)
  508.         {
  509. #ifdef KANJI
  510.           if (is_shift_jis (*p))
  511.         {
  512.           if (extlen < 2)
  513.             {
  514.               extension[extlen++] = p[0];
  515.               extension[extlen++] = p[1];
  516.             }
  517.           else 
  518.             {
  519.               extension[extlen++] = base36 (((unsigned char) *p) % 36);
  520.             }
  521.           p += 2;
  522.         }
  523.           else if (is_kana (*p))
  524.         {
  525.           extension[extlen++] = p[0];
  526.           p++;
  527.         }
  528.           else 
  529.         {
  530.           if (isdoschar (*p) && *p != '.')
  531.             extension[extlen++] = p[0];
  532.           p++;
  533.         }
  534. #else
  535.           if (isdoschar(*p) && *p != '.')
  536.         extension[extlen++] = *p;
  537.           p++;
  538. #endif /* KANJI */
  539.         }
  540.       extension[extlen] = 0;
  541.     }
  542.     }
  543.  
  544.   p = s;
  545.  
  546.   while (*p && baselen < 5)
  547.     {
  548. #ifdef KANJI
  549.       if (is_shift_jis (*p))
  550.     {
  551.       if (baselen < 4)
  552.         {
  553.           base[baselen++] = p[0];
  554.           base[baselen++] = p[1];
  555.         }
  556.       else 
  557.         {
  558.           base[baselen++] = base36 (((unsigned char) *p) % 36);
  559.         }
  560.       p += 2;
  561.     }
  562.       else if (is_kana (*p))
  563.     {
  564.       base[baselen++] = p[0];
  565.       p++;
  566.     }
  567.       else 
  568.     {
  569.       if (isdoschar (*p) && *p != '.')
  570.         base[baselen++] = p[0];
  571.       p++;
  572.     }
  573. #else
  574.       if (isdoschar(*p) && *p != '.')
  575.     base[baselen++] = *p;
  576.       p++;
  577. #endif /* KANJI */
  578.     }
  579.   base[baselen] = 0;
  580.  
  581.   csum = csum % (36*36);
  582.  
  583.     sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
  584.  
  585.   if (*extension)
  586.     {
  587.       strcat(s,".");
  588.       strcat(s,extension);
  589.     }
  590.   DEBUG(5,("%s\n",s));
  591. }
  592.  
  593.  
  594.  
  595. /*******************************************************************
  596.   work out if a name is illegal, even for long names
  597.   ******************************************************************/
  598. static BOOL illegal_name(char *name)
  599. {
  600.   static unsigned char illegal[256];
  601.   static BOOL initialised=False;
  602.   unsigned char *s;
  603.  
  604.   if (!initialised) {
  605.     char *ill = "*\\/?<>|\":{}";
  606.     initialised = True;
  607.   
  608.     bzero((char *)illegal,256);
  609.     for (s = (unsigned char *)ill; *s; s++)
  610.       illegal[*s] = True;
  611.   }
  612.  
  613. #ifdef KANJI
  614.   for (s = (unsigned char *)name; *s;) {
  615.     if (is_shift_jis (*s)) {
  616.       s += 2;
  617.     } else if (illegal[*s]) {
  618.       return(True);
  619.     } else {
  620.       s++;
  621.     }
  622.   }
  623. #else
  624.   for (s = (unsigned char *)name;*s;s++)
  625.     if (illegal[*s]) return(True);
  626. #endif
  627.  
  628.  
  629.   return(False);
  630. }
  631.  
  632.  
  633. /****************************************************************************
  634. convert a filename to DOS format. return True if successful.
  635. ****************************************************************************/
  636. BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
  637. {
  638. #ifdef MANGLE_LONG_FILENAMES
  639.   if (!need83 && illegal_name(OutName)) need83 = True;
  640. #endif  
  641.  
  642.   /* apply any name mappings */
  643.   {
  644.     char *map = lp_mangled_map(snum);
  645.     if (map && *map)
  646.       do_fwd_mangled_map(OutName,map);
  647.   }
  648.  
  649.   /* check if it's already in 8.3 format */
  650.   if (need83 && !is_8_3(OutName, True)) {
  651.     if (!lp_manglednames(snum)) return(False);
  652.  
  653.     /* mangle it into 8.3 */
  654.     push_mangled_name(OutName);  
  655.     mangle_name_83(OutName);
  656.   }
  657.   
  658.   return(True);
  659. }
  660.  
  661.