- (dtucker) [LICENCE configure.ac defines.h openbsd-compat/realpath.c]

Sync current (thread-safe) version of realpath.c from OpenBSD (which is
   in turn based on FreeBSD's).  ok djm@
This commit is contained in:
Darren Tucker 2005-08-10 21:52:36 +10:00
parent c7572b2661
commit 73f671a090
5 changed files with 141 additions and 142 deletions

View File

@ -1,6 +1,9 @@
20050810 20050810
- (dtucker) [configure.ac] Test libedit library and headers for compatibility. - (dtucker) [configure.ac] Test libedit library and headers for compatibility.
Report from skeleten AT shillest.net, ok djm@ Report from skeleten AT shillest.net, ok djm@
- (dtucker) [LICENCE configure.ac defines.h openbsd-compat/realpath.c]
Sync current (thread-safe) version of realpath.c from OpenBSD (which is
in turn based on FreeBSD's). ok djm@
20050809 20050809
- (tim) [configure.ac] Allow --with-audit=no. OK dtucker@ - (tim) [configure.ac] Allow --with-audit=no. OK dtucker@
@ -2904,4 +2907,4 @@
- (djm) Trim deprecated options from INSTALL. Mention UsePAM - (djm) Trim deprecated options from INSTALL. Mention UsePAM
- (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
$Id: ChangeLog,v 1.3864 2005/08/10 10:34:15 dtucker Exp $ $Id: ChangeLog,v 1.3865 2005/08/10 11:52:36 dtucker Exp $

View File

@ -255,6 +255,7 @@ OpenSSH contains no GPL code.
Damien Miller Damien Miller
Eric P. Allman Eric P. Allman
The Regents of the University of California The Regents of the University of California
Constantin S. Svintsoff
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions

View File

@ -1,4 +1,4 @@
# $Id: configure.ac,v 1.284 2005/08/10 10:34:15 dtucker Exp $ # $Id: configure.ac,v 1.285 2005/08/10 11:52:36 dtucker Exp $
# #
# Copyright (c) 1999-2004 Damien Miller # Copyright (c) 1999-2004 Damien Miller
# #
@ -1085,7 +1085,6 @@ AC_CHECK_FUNCS( \
clock \ clock \
closefrom \ closefrom \
dirfd \ dirfd \
fchdir \
fchmod \ fchmod \
fchown \ fchown \
freeaddrinfo \ freeaddrinfo \

View File

@ -25,7 +25,7 @@
#ifndef _DEFINES_H #ifndef _DEFINES_H
#define _DEFINES_H #define _DEFINES_H
/* $Id: defines.h,v 1.122 2005/07/14 07:22:11 dtucker Exp $ */ /* $Id: defines.h,v 1.123 2005/08/10 11:52:36 dtucker Exp $ */
/* Constants */ /* Constants */
@ -62,6 +62,10 @@ enum
# endif /* PATH_MAX */ # endif /* PATH_MAX */
#endif /* MAXPATHLEN */ #endif /* MAXPATHLEN */
#ifndef MAXSYMLINKS
# define MAXSYMLINKS 5
#endif
#ifndef STDIN_FILENO #ifndef STDIN_FILENO
# define STDIN_FILENO 0 # define STDIN_FILENO 0
#endif #endif

View File

@ -1,11 +1,7 @@
/* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */ /* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */
/* /*
* Copyright (c) 1994 * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -15,14 +11,14 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors * 3. The names of the authors may not be used to endorse or promote
* may be used to endorse or promote products derived from this software * products derived from this software without specific prior written
* without specific prior written permission. * permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@ -36,169 +32,165 @@
#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) #if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: realpath.c,v 1.11 2004/11/30 15:12:59 millert Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
/* /*
* MAXSYMLINKS * char *realpath(const char *path, char resolved[PATH_MAX]);
*/
#ifndef MAXSYMLINKS
#define MAXSYMLINKS 5
#endif
/*
* char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
* *
* Find the real name of path, by removing all ".", ".." and symlink * Find the real name of path, by removing all ".", ".." and symlink
* components. Returns (resolved) on success, or (NULL) on failure, * components. Returns (resolved) on success, or (NULL) on failure,
* in which case the path which caused trouble is left in (resolved). * in which case the path which caused trouble is left in (resolved).
*/ */
char * char *
realpath(const char *path, char *resolved) realpath(const char *path, char resolved[PATH_MAX])
{ {
struct stat sb; struct stat sb;
int fd, n, needslash, serrno; char *p, *q, *s;
char *p, *q, wbuf[MAXPATHLEN]; size_t left_len, resolved_len;
int symlinks = 0; unsigned symlinks;
int serrno, slen;
char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
/* Save the starting point. */ serrno = errno;
#ifndef HAVE_FCHDIR symlinks = 0;
char start[MAXPATHLEN]; if (path[0] == '/') {
/* this is potentially racy but without fchdir we have no option */ resolved[0] = '/';
if (getcwd(start, sizeof(start)) == NULL) {
resolved[0] = '.';
resolved[1] = '\0'; resolved[1] = '\0';
return (NULL); if (path[1] == '\0')
} return (resolved);
#endif resolved_len = 1;
if ((fd = open(".", O_RDONLY)) < 0) { left_len = strlcpy(left, path + 1, sizeof(left));
resolved[0] = '.'; } else {
resolved[1] = '\0'; if (getcwd(resolved, PATH_MAX) == NULL) {
return (NULL); strlcpy(resolved, ".", PATH_MAX);
} return (NULL);
/* Convert "." -> "" to optimize away a needless lstat() and chdir() */
if (path[0] == '.' && path[1] == '\0')
path = "";
/*
* Find the dirname and basename from the path to be resolved.
* Change directory to the dirname component.
* lstat the basename part.
* if it is a symlink, read in the value and loop.
* if it is a directory, then change to that directory.
* get the current directory name and append the basename.
*/
if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {
serrno = ENAMETOOLONG;
goto err2;
}
loop:
q = strrchr(resolved, '/');
if (q != NULL) {
p = q + 1;
if (q == resolved)
q = "/";
else {
do {
--q;
} while (q > resolved && *q == '/');
q[1] = '\0';
q = resolved;
}
if (chdir(q) < 0)
goto err1;
} else
p = resolved;
/* Deal with the last component. */
if (*p != '\0' && lstat(p, &sb) == 0) {
if (S_ISLNK(sb.st_mode)) {
if (++symlinks > MAXSYMLINKS) {
errno = ELOOP;
goto err1;
}
if ((n = readlink(p, resolved, MAXPATHLEN-1)) < 0)
goto err1;
resolved[n] = '\0';
goto loop;
}
if (S_ISDIR(sb.st_mode)) {
if (chdir(p) < 0)
goto err1;
p = "";
} }
resolved_len = strlen(resolved);
left_len = strlcpy(left, path, sizeof(left));
} }
if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
/*
* Save the last component name and get the full pathname of
* the current directory.
*/
if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err1; return (NULL);
} }
if (getcwd(resolved, MAXPATHLEN) == NULL)
goto err1;
/* /*
* Join the two strings together, ensuring that the right thing * Iterate over path components in `left'.
* happens if the last component is empty, or the dirname is root.
*/ */
if (resolved[0] == '/' && resolved[1] == '\0') while (left_len != 0) {
needslash = 0; /*
else * Extract the next path component and adjust `left'
needslash = 1; * and its length.
*/
if (*wbuf) { p = strchr(left, '/');
if (strlen(resolved) + strlen(wbuf) + needslash >= MAXPATHLEN) { s = p ? p : left + left_len;
if (s - left >= sizeof(next_token)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err1; return (NULL);
} }
if (needslash) { memcpy(next_token, left, s - left);
if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) { next_token[s - left] = '\0';
left_len -= s - left;
if (p != NULL)
memmove(left, s + 1, left_len + 1);
if (resolved[resolved_len - 1] != '/') {
if (resolved_len + 1 >= PATH_MAX) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err1; return (NULL);
} }
resolved[resolved_len++] = '/';
resolved[resolved_len] = '\0';
} }
if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) { if (next_token[0] == '\0')
continue;
else if (strcmp(next_token, ".") == 0)
continue;
else if (strcmp(next_token, "..") == 0) {
/*
* Strip the last path component except when we have
* single "/"
*/
if (resolved_len > 1) {
resolved[resolved_len - 1] = '\0';
q = strrchr(resolved, '/') + 1;
*q = '\0';
resolved_len = q - resolved;
}
continue;
}
/*
* Append the next path component and lstat() it. If
* lstat() fails we still can return successfully if
* there are no more path components left.
*/
resolved_len = strlcat(resolved, next_token, PATH_MAX);
if (resolved_len >= PATH_MAX) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err1; return (NULL);
}
if (lstat(resolved, &sb) != 0) {
if (errno == ENOENT && p == NULL) {
errno = serrno;
return (resolved);
}
return (NULL);
}
if (S_ISLNK(sb.st_mode)) {
if (symlinks++ > MAXSYMLINKS) {
errno = ELOOP;
return (NULL);
}
slen = readlink(resolved, symlink, sizeof(symlink) - 1);
if (slen < 0)
return (NULL);
symlink[slen] = '\0';
if (symlink[0] == '/') {
resolved[1] = 0;
resolved_len = 1;
} else if (resolved_len > 1) {
/* Strip the last path component. */
resolved[resolved_len - 1] = '\0';
q = strrchr(resolved, '/') + 1;
*q = '\0';
resolved_len = q - resolved;
}
/*
* If there are any path components left, then
* append them to symlink. The result is placed
* in `left'.
*/
if (p != NULL) {
if (symlink[slen - 1] != '/') {
if (slen + 1 >= sizeof(symlink)) {
errno = ENAMETOOLONG;
return (NULL);
}
symlink[slen] = '/';
symlink[slen + 1] = 0;
}
left_len = strlcat(symlink, left, sizeof(left));
if (left_len >= sizeof(left)) {
errno = ENAMETOOLONG;
return (NULL);
}
}
left_len = strlcpy(left, symlink, sizeof(left));
} }
} }
/* Go back to where we came from. */ /*
#ifdef HAVE_FCHDIR * Remove trailing slash except when the resolved pathname
if (fchdir(fd) < 0) { * is a single "/".
#else */
if (chdir(start) < 0) { if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
#endif resolved[resolved_len - 1] = '\0';
serrno = errno;
goto err2;
}
/* It's okay if the close fails, what's an fd more or less? */
(void)close(fd);
return (resolved); return (resolved);
err1: serrno = errno;
#ifdef HAVE_FCHDIR
(void)fchdir(fd);
#else
chdir(start);
#endif
err2: (void)close(fd);
errno = serrno;
return (NULL);
} }
#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ #endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */