home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / mount / realpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  4.0 KB  |  179 lines

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