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