mf_pack.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:15k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include "mysys_priv.h"
  14. #include <m_string.h>
  15. #ifdef HAVE_PWD_H
  16. #include <pwd.h>
  17. #endif
  18. #ifdef VMS
  19. #include <rms.h>
  20. #include <iodef.h>
  21. #include <descrip.h>
  22. #endif /* VMS */
  23. static my_string NEAR_F expand_tilde(my_string *path);
  24. /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
  25. /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
  26. /* to may be == from */
  27. void pack_dirname(my_string to, const char *from)
  28. {
  29.   int cwd_err;
  30.   uint d_length,length,buff_length;
  31.   my_string start;
  32.   char buff[FN_REFLEN];
  33.   DBUG_ENTER("pack_dirname");
  34.   LINT_INIT(buff_length);
  35.   (void) intern_filename(to,from); /* Change to intern name */
  36. #ifdef FN_DEVCHAR
  37.   if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skip device part */
  38.     start++;
  39.   else
  40. #endif
  41.     start=to;
  42.   if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
  43.   {
  44.     buff_length= (uint) strlen(buff);
  45.     d_length=(uint) (start-to);
  46.     if ((start == to ||
  47.  (buff_length == d_length && !bcmp(buff,start,d_length))) &&
  48. *start != FN_LIBCHAR && *start)
  49.     { /* Put current dir before */
  50.       bchange(to,d_length,buff,buff_length,(uint) strlen(to)+1);
  51.     }
  52.   }
  53.   if ((d_length= cleanup_dirname(to,to)) != 0)
  54.   {
  55.     length=0;
  56.     if (home_dir)
  57.     {
  58.       length= (uint) strlen(home_dir);
  59.       if (home_dir[length-1] == FN_LIBCHAR)
  60. length--; /* Don't test last '/' */
  61.     }
  62.     if (length > 1 && length < d_length)
  63.     { /* test if /xx/yy -> ~/yy */
  64.       if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
  65.       {
  66. to[0]=FN_HOMELIB; /* Filename begins with ~ */
  67. (void) strmov_overlapp(to+1,to+length);
  68.       }
  69.     }
  70.     if (! cwd_err)
  71.     { /* Test if cwd is ~/... */
  72.       if (length > 1 && length < buff_length)
  73.       {
  74. if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
  75. {
  76.   buff[0]=FN_HOMELIB;
  77.   (void) strmov_overlapp(buff+1,buff+length);
  78. }
  79.       }
  80.       if (is_prefix(to,buff))
  81.       {
  82. length= (uint) strlen(buff);
  83. if (to[length])
  84.   (void) strmov_overlapp(to,to+length); /* Remove everything before */
  85. else
  86. {
  87.   to[0]= FN_CURLIB; /* Put ./ instead of cwd */
  88.   to[1]= FN_LIBCHAR;
  89.   to[2]= '';
  90. }
  91.       }
  92.     }
  93.   }
  94.   DBUG_PRINT("exit",("to: '%s'",to));
  95.   DBUG_VOID_RETURN;
  96. } /* pack_dirname */
  97. /* remove unwanted chars from dirname */
  98. /* if "/../" removes prev dir; "/~/" removes all before ~ */
  99. /* "//" is same as "/", except on Win32 at start of a file  */
  100. /* "/./" is removed */
  101. /* Unpacks home_dir if "~/.." used */
  102. /* Unpacks current dir if if "./.." used */
  103. uint cleanup_dirname(register my_string to, const char *from)
  104. /* to may be == from */
  105. {
  106.   reg5 uint length;
  107.   reg2 my_string pos;
  108.   reg3 my_string from_ptr;
  109.   reg4 my_string start;
  110.   char parent[5], /* for "FN_PARENTDIR" */
  111.        buff[FN_REFLEN+1],*end_parentdir;
  112. #ifdef BACKSLASH_MBTAIL
  113.   CHARSET_INFO *fs= fs_character_set();
  114. #endif
  115.   DBUG_ENTER("cleanup_dirname");
  116.   DBUG_PRINT("enter",("from: '%s'",from));
  117.   start=buff;
  118.   from_ptr=(my_string) from;
  119. #ifdef FN_DEVCHAR
  120.   if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
  121.   { /* Skip device part */
  122.     length=(uint) (pos-from_ptr)+1;
  123.     start=strnmov(buff,from_ptr,length); from_ptr+=length;
  124.   }
  125. #endif
  126.   parent[0]=FN_LIBCHAR;
  127.   length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
  128.   for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
  129.   {
  130. #ifdef BACKSLASH_MBTAIL
  131.     uint l;
  132.     if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2)))
  133.     {
  134.       for (l-- ; l ; *++pos= *from_ptr++, l--);
  135.       start= pos + 1; /* Don't look inside multi-byte char */
  136.       continue;
  137.     }
  138. #endif
  139.     if (*pos == '/')
  140.       *pos = FN_LIBCHAR;
  141.     if (*pos == FN_LIBCHAR)
  142.     {
  143.       if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
  144.       { /* If .../../; skip prev */
  145. pos-=length;
  146. if (pos != start)
  147. {  /* not /../ */
  148.   pos--;
  149.   if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
  150.   {
  151.     if (!home_dir)
  152.     {
  153.       pos+=length+1; /* Don't unpack ~/.. */
  154.       continue;
  155.     }
  156.     pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
  157.     if (*pos == FN_LIBCHAR)
  158.       pos--; /* home ended with '/' */
  159.   }
  160.   if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
  161.   {
  162.     if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
  163.     {
  164.       pos+=length+1; /* Don't unpack ./.. */
  165.       continue;
  166.     }
  167.     pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
  168.     if (*pos == FN_LIBCHAR)
  169.       pos--; /* home ended with '/' */
  170.   }
  171.   end_parentdir=pos;
  172.   while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
  173.     pos--;
  174.   if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
  175.   { /* Don't remove ~user/ */
  176.     pos=strmov(end_parentdir+1,parent);
  177.     *pos=FN_LIBCHAR;
  178.     continue;
  179.   }
  180. }
  181.       }
  182.       else if ((uint) (pos-start) == length-1 &&
  183.        !bcmp(start,parent+1,length-1))
  184. start=pos; /* Starts with "../" */
  185.       else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
  186.       {
  187. #ifdef FN_NETWORK_DRIVES
  188. if (pos-start != 1)
  189. #endif
  190.   pos--; /* Remove dupplicate '/' */
  191.       }
  192.       else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
  193. pos-=2; /* Skip /./ */
  194.       else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
  195.       { /* Found ..../~/  */
  196. buff[0]=FN_HOMELIB;
  197. buff[1]=FN_LIBCHAR;
  198. start=buff; pos=buff+1;
  199.       }
  200.     }
  201.   }
  202.   (void) strmov(to,buff);
  203.   DBUG_PRINT("exit",("to: '%s'",to));
  204.   DBUG_RETURN((uint) (pos-buff));
  205. } /* cleanup_dirname */
  206. /*
  207.   On system where you don't have symbolic links, the following
  208.   code will allow you to create a file: 
  209.   directory-name.sym that should contain the real path
  210.   to the directory.  This will be used if the directory name
  211.   doesn't exists
  212. */
  213. my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
  214. #ifdef USE_SYMDIR
  215. void symdirget(char *dir)
  216. {
  217.   char buff[FN_REFLEN];
  218.   char *pos=strend(dir);
  219.   if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK))
  220.   {
  221.     File file;
  222.     uint length;
  223.     char temp= *(--pos);            /* May be "/" or "" */
  224.     strmov(pos,".sym");
  225.     file= my_open(dir, O_RDONLY, MYF(0));
  226.     *pos++=temp; *pos=0;   /* Restore old filename */
  227.     if (file >= 0)
  228.     {
  229.       if ((length= my_read(file, buff, sizeof(buff), MYF(0))) > 0)
  230.       {
  231. for (pos= buff + length ;
  232.      pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
  233.      pos --);
  234. /* Ensure that the symlink ends with the directory symbol */
  235. if (pos == buff || pos[-1] != FN_LIBCHAR)
  236.   *pos++=FN_LIBCHAR;
  237. strmake(dir,buff, (uint) (pos-buff));
  238.       }
  239.       my_close(file, MYF(0));
  240.     }
  241.   }
  242. }
  243. #endif /* USE_SYMDIR */
  244. /*
  245.   Fixes a directroy name so that can be used by open()
  246.   SYNOPSIS
  247.     unpack_dirname()
  248.     to Store result here.  May be = from
  249.     from 'Packed' directory name (may contain ~)
  250.  IMPLEMENTATION
  251.   Make that last char of to is '/' if from not empty and
  252.   from doesn't end in FN_DEVCHAR
  253.   Uses cleanup_dirname and changes ~/.. to home_dir/..
  254.   Changes a UNIX filename to system filename (replaces / with  on windows)
  255.   RETURN
  256.    Length of new directory name (= length of to)
  257. */
  258. uint unpack_dirname(my_string to, const char *from)
  259. {
  260.   uint length,h_length;
  261.   char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
  262.   DBUG_ENTER("unpack_dirname");
  263.   (void) intern_filename(buff,from); /* Change to intern name */
  264.   length= (uint) strlen(buff); /* Fix that '/' is last */
  265.   if (length &&
  266. #ifdef FN_DEVCHAR
  267.       buff[length-1] != FN_DEVCHAR &&
  268. #endif
  269.       buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
  270.   {
  271.     buff[length]=FN_LIBCHAR;
  272.     buff[length+1]= '';
  273.   }
  274.   length=cleanup_dirname(buff,buff);
  275.   if (buff[0] == FN_HOMELIB)
  276.   {
  277.     suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
  278.     if (tilde_expansion)
  279.     {
  280.       length-=(uint) (suffix-buff)-1;
  281.       if (length+(h_length= (uint) strlen(tilde_expansion)) <= FN_REFLEN)
  282.       {
  283. if (tilde_expansion[h_length-1] == FN_LIBCHAR)
  284.   h_length--;
  285. if (buff+h_length < suffix)
  286.   bmove(buff+h_length,suffix,length);
  287. else
  288.   bmove_upp(buff+h_length+length,suffix+length,length);
  289. bmove(buff,tilde_expansion,h_length);
  290.       }
  291.     }
  292.   }
  293. #ifdef USE_SYMDIR
  294.   if (my_use_symdir)
  295.     symdirget(buff);
  296. #endif
  297.   DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
  298. } /* unpack_dirname */
  299. /* Expand tilde to home or user-directory */
  300. /* Path is reset to point at FN_LIBCHAR after ~xxx */
  301. static my_string NEAR_F expand_tilde(my_string *path)
  302. {
  303.   if (path[0][0] == FN_LIBCHAR)
  304.     return home_dir; /* ~/ expanded to home */
  305. #ifdef HAVE_GETPWNAM
  306.   {
  307.     char *str,save;
  308.     struct passwd *user_entry;
  309.     if (!(str=strchr(*path,FN_LIBCHAR)))
  310.       str=strend(*path);
  311.     save= *str; *str= '';
  312.     user_entry=getpwnam(*path);
  313.     *str=save;
  314.     endpwent();
  315.     if (user_entry)
  316.     {
  317.       *path=str;
  318.       return user_entry->pw_dir;
  319.     }
  320.   }
  321. #endif
  322.   return (my_string) 0;
  323. }
  324. /*
  325.   Fix filename so it can be used by open, create
  326.   SYNOPSIS
  327.     unpack_filename()
  328.     to Store result here. Must be at least of size FN_REFLEN.
  329.     from Filename in unix format (with ~)
  330.   RETURN
  331.     # length of to
  332.   NOTES
  333.     to may be == from
  334.     ~ will only be expanded if total length < FN_REFLEN
  335. */
  336. uint unpack_filename(my_string to, const char *from)
  337. {
  338.   uint length,n_length;
  339.   char buff[FN_REFLEN];
  340.   DBUG_ENTER("unpack_filename");
  341.   length=dirname_part(buff,from); /* copy & convert dirname */
  342.   n_length=unpack_dirname(buff,buff);
  343.   if (n_length+strlen(from+length) < FN_REFLEN)
  344.   {
  345.     (void) strmov(buff+n_length,from+length);
  346.     length= system_filename(to,buff); /* Fix to usably filename */
  347.   }
  348.   else
  349.     length= system_filename(to,from); /* Fix to usably filename */
  350.   DBUG_RETURN(length);
  351. } /* unpack_filename */
  352. /* Convert filename (unix standard) to system standard */
  353. /* Used before system command's like open(), create() .. */
  354. /* Returns length of to */
  355. uint system_filename(my_string to, const char *from)
  356. {
  357. #ifndef FN_C_BEFORE_DIR
  358.   return (uint) (strmake(to,from,FN_REFLEN-1)-to);
  359. #else /* VMS */
  360. /* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
  361. /* change 'dev:xxx' to 'dev:xxx' */
  362. /* change './xxx' to 'xxx' */
  363. /* change './lib/' or lib/ to '[.lib]' */
  364. /* change '/x/y/z to '[x.y]x' */
  365. /* change 'dev:/x' to 'dev:[000000]x' */
  366.   int libchar_found,length;
  367.   my_string to_pos,from_pos,pos;
  368.   char buff[FN_REFLEN];
  369.   DBUG_ENTER("system_filename");
  370.   libchar_found=0;
  371.   (void) strmov(buff,from);  /* If to == from */
  372.   from_pos= buff;
  373.   if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skip device part */
  374.   {
  375.     pos++;
  376.     to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
  377.     from_pos=pos;
  378.   }
  379.   else
  380.     to_pos=to;
  381.   if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
  382.     from_pos+=2; /* Skip './' */
  383.   if (strchr(from_pos,FN_LIBCHAR))
  384.   {
  385.     *(to_pos++) = FN_C_BEFORE_DIR;
  386.     if (strinstr(from_pos,FN_ROOTDIR) == 1)
  387.     {
  388.       from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
  389.       if (! strchr(from_pos,FN_LIBCHAR))
  390.       { /* No dir, use [000000] */
  391. to_pos=strmov(to_pos,FN_C_ROOT_DIR);
  392. libchar_found++;
  393.       }
  394.     }
  395.     else
  396.       *(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
  397.     while ((pos=strchr(from_pos,FN_LIBCHAR)))
  398.     {
  399.       if (libchar_found++)
  400. *(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
  401.       if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
  402.   from_pos+strlen(FN_PARENTDIR) == pos)
  403. to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
  404.       else
  405. to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
  406.       from_pos=pos+1;
  407.     }
  408.     *(to_pos++)=FN_C_AFTER_DIR;
  409.   }
  410.   length=(int) (strmov(to_pos,from_pos)-to);
  411.   DBUG_PRINT("exit",("name: '%s'",to));
  412.   DBUG_RETURN((uint) length);
  413. #endif
  414. } /* system_filename */
  415. /* Fix a filename to intern (UNIX format) */
  416. my_string intern_filename(my_string to, const char *from)
  417. {
  418. #ifndef VMS
  419.   {
  420.     uint length;
  421.     char buff[FN_REFLEN];
  422.     if (from == to)
  423.     { /* Dirname may destroy from */
  424.       strmov(buff,from);
  425.       from=buff;
  426.     }
  427.     length=dirname_part(to,from); /* Copy dirname & fix chars */
  428.     (void) strcat(to,from+length);
  429.     return (to);
  430.   }
  431. #else /* VMS */
  432. /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
  433. /* change 'dev:xxx' to 'dev:xxx' */
  434. /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
  435. /* change '[.lib]' to './lib/' */
  436. /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
  437. /* change '[000000.x] or [x.000000]' to '/x/' */
  438.   int par_length,root_length;
  439.   my_string pos,from_pos,to_pos,end_pos;
  440.   char buff[FN_REFLEN];
  441.   convert_dirname(buff,from,NullS); /* change '<>' to '[]' */
  442.   from_pos=buff;
  443.   if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skip device part */
  444.   {
  445.     pos++;
  446.     to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
  447.     from_pos=pos;
  448.   }
  449.   else
  450.     to_pos=to;
  451.   root_length=strlen(FN_C_ROOT_DIR);
  452.   if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
  453.       (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
  454.   {
  455.     to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
  456. /* Copy all between ':' and '[' */
  457.     from_pos=pos+1;
  458.     if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
  459. (from_pos[root_length] == FN_C_DIR_SEP ||
  460.  from_pos[root_length] == FN_C_AFTER_DIR))
  461.     {
  462.       from_pos+=root_length+1;
  463.     }
  464.     else if (*from_pos == FN_C_DIR_SEP)
  465.       *(to_pos++) = FN_CURLIB; /* Set ./ first */
  466.     *(to_pos++) = FN_LIBCHAR;
  467.     par_length=strlen(FN_C_PARENT_DIR);
  468.     pos=to_pos;
  469.     for (; from_pos <= end_pos ; from_pos++)
  470.     {
  471.       switch (*from_pos) {
  472.       case FN_C_DIR_SEP:
  473.       case FN_C_AFTER_DIR:
  474. if (pos != to_pos)
  475. {
  476.   if ((int) (to_pos-pos) == root_length &&
  477.       is_suffix(pos,FN_C_ROOT_DIR))
  478.     to_pos=pos; /* remove root-pos */
  479.   else
  480.   {
  481.     *(to_pos++)=FN_LIBCHAR; /* Find lib */
  482.     pos=to_pos;
  483.   }
  484. }
  485. break;
  486.       case FN_C_BEFORE_DIR:
  487. break;
  488.       case '-': /* *(FN_C_PARENT_DIR): */
  489. if (to_pos[-1] == FN_LIBCHAR &&
  490.     strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
  491. { /* Change '-' to '..' */
  492.   to_pos=strmov(to_pos,FN_PARENTDIR);
  493.   *(to_pos++)=FN_LIBCHAR;
  494.   pos=to_pos;
  495.   from_pos+=par_length-1;
  496.   break;
  497. }
  498. /* Fall through */
  499.       default:
  500. *(to_pos++)= *from_pos;
  501. break;
  502.       }
  503.     }
  504.   }
  505.   (void) strmov(to_pos,from_pos);
  506.   return (to);
  507. #endif /* VMS */
  508. } /* intern_filename */