1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1989, 1991, 1993, 1995 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36#if defined(LIBC_SCCS) && !defined(lint) 37#if 0 38static char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95"; 39#else 40__RCSID("$NetBSD$"); 41#endif 42#endif /* LIBC_SCCS and not lint */ 43 44#include "namespace.h" 45#include <sys/param.h> 46#include <sys/stat.h> 47 48#include <assert.h> 49#include <errno.h> 50#include <stdlib.h> 51#include <string.h> 52#include <unistd.h> 53#include <ssp/ssp.h> 54 55#include "extern.h" 56 57#ifdef __weak_alias 58__weak_alias(getcwd,_getcwd) 59__weak_alias(_sys_getcwd,_getcwd) 60__weak_alias(realpath,_realpath) 61#endif 62 63/* 64 * char *realpath(const char *path, char *resolved); 65 * 66 * Find the real name of path, by removing all ".", ".." and symlink 67 * components. Returns (resolved) on success, or (NULL) on failure, 68 * in which case the path which caused trouble is left in (resolved). 69 */ 70char * 71realpath(const char * __restrict path, char * __restrict resolved) 72{ 73 struct stat sb; 74 int idx = 0, n, nlnk = 0; 75 const char *q; 76 char *p, wbuf[2][MAXPATHLEN], *fres; 77 size_t len; 78 79 /* POSIX sez we must test for this */ 80 if (path == NULL) { 81 errno = EINVAL; 82 return NULL; 83 } 84 85 if (resolved == NULL) { 86 fres = resolved = malloc(MAXPATHLEN); 87 if (resolved == NULL) 88 return NULL; 89 } else 90 fres = NULL; 91 92 93 /* 94 * Build real path one by one with paying an attention to ., 95 * .. and symbolic link. 96 */ 97 98 /* 99 * `p' is where we'll put a new component with prepending 100 * a delimiter. 101 */ 102 p = resolved; 103 104 if (*path == '\0') { 105 *p = '\0'; 106 errno = ENOENT; 107 goto out; 108 } 109 110 /* If relative path, start from current working directory. */ 111 if (*path != '/') { 112 /* check for resolved pointer to appease coverity */ 113 if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { 114 p[0] = '.'; 115 p[1] = '\0'; 116 goto out; 117 } 118 len = strlen(resolved); 119 if (len > 1) 120 p += len; 121 } 122 123loop: 124 /* Skip any slash. */ 125 while (*path == '/') 126 path++; 127 128 if (*path == '\0') { 129 if (p == resolved) 130 *p++ = '/'; 131 *p = '\0'; 132 return resolved; 133 } 134 135 /* Find the end of this component. */ 136 q = path; 137 do 138 q++; 139 while (*q != '/' && *q != '\0'); 140 141 /* Test . or .. */ 142 if (path[0] == '.') { 143 if (q - path == 1) { 144 path = q; 145 goto loop; 146 } 147 if (path[1] == '.' && q - path == 2) { 148 /* Trim the last component. */ 149 if (p != resolved) 150 while (*--p != '/') 151 continue; 152 path = q; 153 goto loop; 154 } 155 } 156 157 /* Append this component. */ 158 if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) { 159 errno = ENAMETOOLONG; 160 if (p == resolved) 161 *p++ = '/'; 162 *p = '\0'; 163 goto out; 164 } 165 p[0] = '/'; 166 memcpy(&p[1], path, 167 /* LINTED We know q > path. */ 168 q - path); 169 p[1 + q - path] = '\0'; 170 171 /* 172 * If this component is a symlink, toss it and prepend link 173 * target to unresolved path. 174 */ 175 if (lstat(resolved, &sb) == -1) 176 goto out; 177 178 if (S_ISLNK(sb.st_mode)) { 179 if (nlnk++ >= MAXSYMLINKS) { 180 errno = ELOOP; 181 goto out; 182 } 183 n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); 184 if (n < 0) 185 return (NULL); 186 if (n == 0) { 187 errno = ENOENT; 188 goto out; 189 } 190 191 /* Append unresolved path to link target and switch to it. */ 192 if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { 193 errno = ENAMETOOLONG; 194 goto out; 195 } 196 memcpy(&wbuf[idx][n], q, len + 1); 197 path = wbuf[idx]; 198 idx ^= 1; 199 200 /* If absolute symlink, start from root. */ 201 if (*path == '/') 202 p = resolved; 203 goto loop; 204 } 205 if (*q == '/' && !S_ISDIR(sb.st_mode)) { 206 errno = ENOTDIR; 207 goto out; 208 } 209 210 /* Advance both resolved and unresolved path. */ 211 p += 1 + q - path; 212 path = q; 213 goto loop; 214out: 215 free(fres); 216 return NULL; 217} 218 219char * 220__ssp_real(getcwd)(char *pt, size_t size) 221{ 222 char *npt; 223 224 /* 225 * If a buffer is specified, the size has to be non-zero. 226 */ 227 if (pt != NULL) { 228 if (size == 0) { 229 /* __getcwd(pt, 0) results ERANGE. */ 230 errno = EINVAL; 231 return (NULL); 232 } 233 if (__getcwd(pt, size) >= 0) 234 return (pt); 235 return (NULL); 236 } 237 238 /* 239 * If no buffer specified by the user, allocate one as necessary. 240 */ 241 size = 1024 >> 1; 242 do { 243 if ((npt = realloc(pt, size <<= 1)) == NULL) 244 break; 245 pt = npt; 246 if (__getcwd(pt, size) >= 0) 247 return (pt); 248 } while (size <= MAXPATHLEN * 4 && errno == ERANGE); 249 250 free(pt); 251 return (NULL); 252} 253