realpath.c
上传用户:shenzhenrh
上传日期:2013-05-12
资源大小:2904k
文件大小:9k
源码类别:

信息检索与抽取

开发平台:

Unix_Linux

  1. #include <sys/param.h>
  2. #include <unistd.h>
  3. #include <errno.h>
  4. #include "misc.h"
  5. #ifdef __CYGWIN__
  6. #define PATHNAME_UNIX_UNC
  7. int readlink (const char *, char *, int);
  8. #endif
  9. #ifndef MAXSYMLINKS
  10. /* Cygwin and libc1 GNU/Linux machines lack this in sys/param.h. */
  11. #define MAXSYMLINKS 10
  12. #endif
  13. #ifndef __MINGW32__
  14. #define HAVE_READLINK
  15. #endif
  16. #ifdef ELOOP
  17. #define ELOOP_VALUE ELOOP
  18. #else
  19. #define ELOOP_VALUE 999
  20. #endif
  21. /* Library-Funktion realpath implementieren:
  22.    [Copyright: SUN Microsystems, B. Haible]
  23.    TITLE
  24.    REALPATH(3)
  25.    SYNOPSIS
  26.    char* realpath (const char* path, char resolved_path[MAXPATHLEN]);
  27.    DESCRIPTION
  28.    realpath() expands all symbolic links  and  resolves  refer-
  29.    ences  to '/./', '/../' and extra '/' characters in the null
  30.    terminated string named by path and stores the canonicalized
  31.    absolute pathname in the buffer named by resolved_path.  The
  32.    resulting path will have no symbolic links  components,  nor
  33.    any '/./' or '/../' components.
  34.    RETURN VALUES
  35.    realpath() returns a pointer to the  resolved_path  on  suc-
  36.    cess.   On  failure, it returns NULL, sets errno to indicate
  37.    the error, and places in resolved_path the absolute pathname
  38.    of the path component which could not be resolved. 
  39. */
  40. const char *
  41. realpath (const char *path, char *resolved_path)
  42. /* Methode: benutze getwd und readlink. */
  43. {
  44.   char mypath[MAXPATHLEN];
  45.   int symlinkcount = 0; /* Anzahl bisher aufgetretener symbolischer Links */
  46.   char* resolved_limit = &resolved_path[MAXPATHLEN-1];
  47.   /* G黮tige Pointer sind die mit resolved_path <= ptr <= resolved_limit.
  48.      In *resolved_limit darf h鯿hstens noch ein Nullbyte stehen.
  49.      (Analog mit mypath.) */
  50.   char* resolve_start;
  51.   {
  52.     char* resolved_ptr = resolved_path; /* (bleibt stets <= resolved_limit) */
  53.     /* evtl. Working-Directory benutzen: */
  54.     if (!(path[0]=='/')) /* kein absoluter Pathname ? */
  55.       { 
  56.         if (getcwd (resolved_path, MAXPATHLEN) == NULL)
  57.           return NULL;
  58.         resolved_ptr = resolved_path;
  59.         while (*resolved_ptr) { resolved_ptr++; }
  60.         if (resolved_ptr < resolved_limit)
  61.           *resolved_ptr++ = '/';
  62.         resolve_start = resolved_ptr;
  63.       }
  64.     else
  65.       resolve_start = resolved_ptr = &resolved_path[0];
  66.     /* Dann path selber einkopieren: */
  67.     {
  68.       const char* path_ptr = path;
  69.       
  70.       while ((resolved_ptr < resolved_limit) && *path_ptr)
  71.         *resolved_ptr++ = *path_ptr++;
  72.       /* Mit '/' und einem Nullbyte abschlie遝n:*/
  73.       if (resolved_ptr < resolved_limit)
  74.         *resolved_ptr++ = '/';
  75.       *resolved_ptr = 0;
  76.     }
  77.   }
  78.   /* Los geht's nun in resolved_path ab resolve_start.  */
  79.   {
  80.     char *from_ptr = resolve_start;
  81.     char *to_ptr = resolve_start;
  82.     while ((to_ptr < resolved_limit) && (*from_ptr))
  83.       /* Bis hierher hat der Pfad in  resolved_path[0]...to_ptr[-1]
  84.          die Gestalt '/subdir1/subdir2/.../txt', 
  85.          wobei 'txt' evtl. leer, aber kein subdir leer. */
  86.       {
  87.         char next = *from_ptr++; *to_ptr++ = next;
  88.         if ((next == '/') && (to_ptr > resolved_path+1))
  89.           /* to_ptr[-1]='/'  ->  Directory ...to_ptr[-2] aufl鰏en: */
  90.           {
  91.             char* last_subdir_end = &to_ptr[-2];
  92.             switch (*last_subdir_end)
  93.               {
  94.               case '/':
  95. #ifdef PATHNAME_UNIX_UNC
  96.                 if (to_ptr > resolved_path+2)
  97. #endif
  98.                   /* '//' wird zu '/' vereinfacht: */
  99.                   to_ptr--;
  100.                 break;
  101.               case '.':
  102.                 {
  103.                   char* last_subdir_ptr = &last_subdir_end[-1];
  104.                   if (to_ptr > resolved_path+2)
  105.                     { if (*last_subdir_ptr == '.')
  106.                       {
  107.                         if ((to_ptr > resolved_path+4) && (*--last_subdir_ptr == '/'))
  108.                           /* letztes subdir war '/../' */
  109.                           /* Daf黵 das subdir davor entfernen: */
  110.                           {
  111.                             while ((last_subdir_ptr > resolved_path) && !(*--last_subdir_ptr == '/'));
  112.                             to_ptr = last_subdir_ptr+1;
  113.                           }
  114.                       }
  115.                     else if (*last_subdir_ptr == '/')
  116.                       {
  117.                         /*  letztes subdir war '/./'
  118.                             entfernen: */
  119.                         to_ptr = last_subdir_end;
  120.                       }
  121.                     }
  122.                 }
  123.                 break;
  124.               default:
  125.                 /* nach einem normalen subdir */
  126. #ifdef HAVE_READLINK
  127.                 /* symbolischen Link lesen: */
  128.                 to_ptr[-1]=0; /* '/' durch 0 ersetzen */
  129.                   {
  130. #if defined( __CYGWIN__) && 0
  131.                     /* needed for Win95 only
  132.                        readlink() doesn't work right on NFS mounted directories
  133.                        (it returns -1,ENOENT or -1,EIO).
  134.                        So check for a directory first. */
  135.                     struct stat statbuf;
  136.                     if (lstat(resolved_path,&statbuf) < 0)
  137.                       return NULL; /* Fehler */
  138.                     if (S_ISDIR(statbuf.st_mode))
  139.                       /* Verzeichnis, kein symbolisches Link */
  140.                       to_ptr[-1] = '/'; /* wieder den '/' eintragen */
  141.                     else
  142. #endif
  143.                       { 
  144.                         int linklen = readlink(resolved_path,mypath,sizeof(mypath)-1);
  145.                         if (linklen >=0)
  146.                           /* war ein symbolisches Link */
  147.                           {
  148.                             if (++symlinkcount > MAXSYMLINKS)
  149.                               {
  150.                                 errno = ELOOP_VALUE;
  151.                                 return NULL;
  152.                               }
  153.                             /* noch aufzul鰏enden path-Anteil an den Link-Inhalt anh鋘gen: */
  154.                             {
  155.                               char* mypath_ptr = &mypath[linklen]; /* ab hier ist Platz */
  156.                               char* mypath_limit = &mypath[MAXPATHLEN-1]; /* bis hierher */
  157.                               if (mypath_ptr < mypath_limit) { *mypath_ptr++ = '/'; } /* erst ein '/' anh鋘gen */
  158.                               /* dann den Rest: */
  159.                               while ((mypath_ptr <= mypath_limit) && (*mypath_ptr = *from_ptr++))
  160.                                 mypath_ptr++;
  161.                               *mypath_ptr = 0; /* und mit 0 abschlie遝n */
  162.                             }
  163.                             /* Dies ersetzt bzw. erg鋘zt den path: */
  164.                             if (mypath[0] == '/')
  165.                               /* ersetzt den path: */
  166.                               {
  167.                                 from_ptr = &mypath[0]; to_ptr = resolved_path;
  168.                                 while ((*to_ptr++ = *from_ptr++));
  169.                                 from_ptr = resolved_path;
  170.                               }
  171.                             else
  172.                               /* erg鋘zt den path: */
  173.                                 { 
  174.                                   /* Linknamen streichen. Dazu bis zum letzten '/' suchen: */
  175.                                   {
  176.                                     char* ptr = &to_ptr[-1];
  177.                                     while ((ptr > resolved_path) && !(ptr[-1] == '/'))
  178.                                       ptr--;
  179.                                     from_ptr = ptr;
  180.                                   }
  181.                                   {
  182.                                     char* mypath_ptr = &mypath[0]; to_ptr = from_ptr;
  183.                                     while ((to_ptr <= resolved_limit) && (*to_ptr++ = *mypath_ptr++));
  184.                                   }
  185.                                 }
  186.                             to_ptr = from_ptr;
  187.                           }
  188.                         else
  189. #if (defined(sgi) || defined(__sgi))
  190.                           if ((errno == EINVAL) || (errno == ENXIO))
  191. #elif defined(__MINT__)
  192.                             if ((errno == EINVAL) || (errno == EACCESS))
  193. #elif defined(__CYGWIN__)
  194.                               if ((errno == EINVAL) || (errno == EACCES))
  195. #else
  196.                                 if (errno == EINVAL)
  197. #endif
  198.                                   /* kein symbolisches Link */
  199.                                   to_ptr[-1] = '/'; /* wieder den '/' eintragen */
  200.                                 else
  201.                                   return NULL; /* Fehler */
  202.                       }
  203.                   }
  204. #endif
  205.                 break;
  206.               }
  207.           }
  208.       }
  209.     /* dann zum n鋍hsten subdir
  210.        ein '/' am Ende streichen: */
  211.     if ((to_ptr[-1] == '/')
  212. #ifdef PATHNAME_UNIX_UNC
  213.         && (to_ptr > resolved_path+2)
  214. #else
  215.         && (to_ptr > resolved_path+1)
  216. #endif
  217.         )
  218.       to_ptr--;
  219.     to_ptr[0] = 0; /* durch 0 abschlie遝n */
  220.     return resolved_path; /* fertig */
  221.   }
  222. }