Mercurial > hg > xemacs-beta
diff src/realpath.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | a2f645c6b9f8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/realpath.c Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,200 @@ +/* + * realpath.c -- canonicalize pathname by removing symlinks + * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> + * + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +#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> +#include <string.h> +#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 + /* 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 + { + /* Protect against infinite loops. */ + if (readlinks++ > MAX_READLINKS) + { + errno = ELOOP; + return NULL; + } + + /* 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; +}