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