home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / realpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-11  |  4.2 KB  |  200 lines

  1. /*
  2.  * realpath.c -- canonicalize pathname by removing symlinks
  3.  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  4.  *
  5.  
  6. This file is part of XEmacs.
  7.  
  8. XEmacs is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with XEmacs; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. /* Synched up with: Not in FSF. */
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27.  
  28. #include <sys/types.h>
  29. #if defined(HAVE_UNISTD_H) || defined(STDC_HEADERS)
  30. #include <unistd.h>
  31. #endif
  32. #include <stdio.h>
  33. #include <string.h>
  34. #ifdef _POSIX_VERSION
  35. #include <limits.h>            /* for PATH_MAX */
  36. #else
  37. #include <sys/param.h>            /* for MAXPATHLEN */
  38. #endif
  39. #include <errno.h>
  40. #ifndef STDC_HEADERS
  41. extern int errno;
  42. #endif
  43.  
  44. #include <sys/stat.h>            /* for S_IFLNK */
  45.  
  46. #ifndef PATH_MAX
  47. #ifdef _POSIX_VERSION
  48. #define PATH_MAX _POSIX_PATH_MAX
  49. #else
  50. #ifdef MAXPATHLEN
  51. #define PATH_MAX MAXPATHLEN
  52. #else
  53. #define PATH_MAX 1024
  54. #endif
  55. #endif
  56. #endif
  57.  
  58. #define MAX_READLINKS 32
  59.  
  60. #ifdef __STDC__
  61. char *realpath(const char *path, char resolved_path [])
  62. #else
  63. char *realpath(path, resolved_path)
  64. const char *path;
  65. char resolved_path [];
  66. #endif
  67. {
  68.   char copy_path[PATH_MAX];
  69.   char link_path[PATH_MAX];
  70.   char *new_path = resolved_path;
  71.   char *max_path;
  72.   int readlinks = 0;
  73.   int n;
  74.  
  75.   /* Make a copy of the source path since we may need to modify it. */
  76.   strcpy(copy_path, path);
  77.   path = copy_path;
  78.   max_path = copy_path + PATH_MAX - 2;
  79.   /* If it's a relative pathname use getwd for starters. */
  80.   if (*path != '/')
  81.     {
  82. #ifdef HAVE_GETCWD
  83.       getcwd(new_path, PATH_MAX - 1);
  84. #else
  85.       getwd(new_path);
  86. #endif
  87.       new_path += strlen(new_path);
  88.       if (new_path[-1] != '/')
  89.     *new_path++ = '/';
  90.     }
  91.   else
  92.     {
  93.       *new_path++ = '/';
  94.       path++;
  95.     }
  96.  
  97.   /* Expand each slash-separated pathname component. */
  98.   while (*path != '\0')
  99.     {
  100.       /* Ignore stray "/". */
  101.       if (*path == '/')
  102.     {
  103.       path++;
  104.       continue;
  105.     }
  106.  
  107.       if (*path == '.')
  108.     {
  109.       /* Ignore ".". */
  110.       if (path[1] == '\0' || path[1] == '/')
  111.         {
  112.           path++;
  113.           continue;
  114.         }
  115.  
  116.       if (path[1] == '.')
  117.         {
  118.           if (path[2] == '\0' || path[2] == '/')
  119.         {
  120.           path += 2;
  121.  
  122.           /* Ignore ".." at root. */
  123.           if (new_path == resolved_path + 1)
  124.             continue;
  125.  
  126.           /* Handle ".." by backing up. */
  127.           while ((--new_path)[-1] != '/')
  128.             ;
  129.           continue;
  130.         }
  131.         }
  132.     }
  133.  
  134.       /* Safely copy the next pathname component. */
  135.       while (*path != '\0' && *path != '/')
  136.     {
  137.       if (path > max_path)
  138.         {
  139.           errno = ENAMETOOLONG;
  140.           return NULL;
  141.         }
  142.       *new_path++ = *path++;
  143.     }
  144.  
  145. #ifdef S_IFLNK
  146.       /* See if latest pathname component is a symlink. */
  147.       *new_path = '\0';
  148.       n = readlink(resolved_path, link_path, PATH_MAX - 1);
  149.  
  150.       if (n < 0)
  151.     {
  152.       /* EINVAL means the file exists but isn't a symlink. */
  153.       if (errno != EINVAL)
  154.         return NULL;
  155.     }
  156.       else
  157.     {
  158.       /* Protect against infinite loops. */
  159.       if (readlinks++ > MAX_READLINKS)
  160.         {
  161.           errno = ELOOP;
  162.           return NULL;
  163.         }
  164.  
  165.       /* Note: readlink doesn't add the null byte. */
  166.       link_path[n] = '\0';
  167.  
  168.       if (*link_path == '/')
  169.         /* Start over for an absolute symlink. */
  170.         new_path = resolved_path;
  171.       else
  172.         /* Otherwise back up over this component. */
  173.         while (*(--new_path) != '/')
  174.           ;
  175.  
  176.       /* Safe sex check. */
  177.       if (strlen(path) + n >= PATH_MAX)
  178.         {
  179.           errno = ENAMETOOLONG;
  180.           return NULL;
  181.         }
  182.  
  183.       /* Insert symlink contents into path. */
  184.       strcat(link_path, path);
  185.       strcpy(copy_path, link_path);
  186.       path = copy_path;
  187.     }
  188. #endif /* S_IFLNK */
  189.       *new_path++ = '/';
  190.     }
  191.  
  192.   /* Delete trailing slash but don't whomp a lone slash. */
  193.   if (new_path != resolved_path + 1 && new_path[-1] == '/')
  194.     new_path--;
  195.  
  196.   /* Make sure it's null terminated. */
  197.   *new_path = '\0';
  198.   return resolved_path;
  199. }
  200.