1 /* Return the canonical absolute name of a given file. 2 Copyright (C) 1996-2003, 2005-2006 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, write to the Free 17 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 MA 02110-1301, USA. */ 19 20 #include <config.h> 21 22 /* Avoid a clash of our rpl_realpath() function with the prototype in 23 <stdlib.h> on Solaris 2.5.1. */ 24 #undef realpath 25 26 #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC 27 28 #include <alloca.h> 29 30 /* Specification. */ 31 #include "canonicalize.h" 32 33 #include <stddef.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 #if HAVE_UNISTD_H || defined _LIBC 38 # include <unistd.h> 39 #endif 40 41 #include <limits.h> 42 43 #if HAVE_SYS_PARAM_H || defined _LIBC 44 # include <sys/param.h> 45 #endif 46 #ifndef MAXSYMLINKS 47 # define MAXSYMLINKS 20 48 #endif 49 50 #include <sys/stat.h> 51 52 #include <errno.h> 53 #ifndef _LIBC 54 # define __set_errno(e) errno = (e) 55 # ifndef ENAMETOOLONG 56 # define ENAMETOOLONG EINVAL 57 # endif 58 #endif 59 60 #ifdef _LIBC 61 # include <shlib-compat.h> 62 #else 63 # define SHLIB_COMPAT(lib, introduced, obsoleted) 0 64 # define versioned_symbol(lib, local, symbol, version) 65 # define compat_symbol(lib, local, symbol, version) 66 # define weak_alias(local, symbol) 67 # define __canonicalize_file_name canonicalize_file_name 68 # define __realpath rpl_realpath 69 # include "pathmax.h" 70 # include "allocsa.h" 71 # if HAVE_GETCWD 72 # ifdef VMS 73 /* We want the directory in Unix syntax, not in VMS syntax. */ 74 # define __getcwd(buf, max) getcwd (buf, max, 0) 75 # else 76 # define __getcwd getcwd 77 # endif 78 # else 79 # define __getcwd(buf, max) getwd (buf) 80 # endif 81 # define __readlink readlink 82 /* On systems without symbolic links, call stat() instead of lstat(). */ 83 # if !defined S_ISNLK && !HAVE_READLINK 84 # define lstat stat 85 # endif 86 #endif 87 88 /* Return the canonical absolute name of file NAME. A canonical name 89 does not contain any `.', `..' components nor any repeated path 90 separators ('/') or symlinks. All path components must exist. If 91 RESOLVED is null, the result is malloc'd; otherwise, if the 92 canonical name is PATH_MAX chars or more, returns null with `errno' 93 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, 94 returns the name in RESOLVED. If the name cannot be resolved and 95 RESOLVED is non-NULL, it contains the path of the first component 96 that cannot be resolved. If the path can be resolved, RESOLVED 97 holds the same value as the value returned. */ 98 99 char * 100 __realpath (const char *name, char *resolved) 101 { 102 char *rpath, *dest, *extra_buf = NULL; 103 const char *start, *end, *rpath_limit; 104 long int path_max; 105 #ifdef S_ISLNK 106 int num_links = 0; 107 #endif 108 109 if (name == NULL) 110 { 111 /* As per Single Unix Specification V2 we must return an error if 112 either parameter is a null pointer. We extend this to allow 113 the RESOLVED parameter to be NULL in case the we are expected to 114 allocate the room for the return value. */ 115 __set_errno (EINVAL); 116 return NULL; 117 } 118 119 if (name[0] == '\0') 120 { 121 /* As per Single Unix Specification V2 we must return an error if 122 the name argument points to an empty string. */ 123 __set_errno (ENOENT); 124 return NULL; 125 } 126 127 #ifdef PATH_MAX 128 path_max = PATH_MAX; 129 #else 130 path_max = pathconf (name, _PC_PATH_MAX); 131 if (path_max <= 0) 132 path_max = 1024; 133 #endif 134 135 if (resolved == NULL) 136 { 137 rpath = malloc (path_max); 138 if (rpath == NULL) 139 return NULL; 140 } 141 else 142 rpath = resolved; 143 rpath_limit = rpath + path_max; 144 145 if (name[0] != '/') 146 { 147 if (!__getcwd (rpath, path_max)) 148 { 149 rpath[0] = '\0'; 150 goto error; 151 } 152 dest = strchr (rpath, '\0'); 153 } 154 else 155 { 156 rpath[0] = '/'; 157 dest = rpath + 1; 158 } 159 160 for (start = end = name; *start; start = end) 161 { 162 #ifdef _LIBC 163 struct stat64 st; 164 #else 165 struct stat st; 166 #endif 167 168 /* Skip sequence of multiple path-separators. */ 169 while (*start == '/') 170 ++start; 171 172 /* Find end of path component. */ 173 for (end = start; *end && *end != '/'; ++end) 174 /* Nothing. */; 175 176 if (end - start == 0) 177 break; 178 else if (end - start == 1 && start[0] == '.') 179 /* nothing */; 180 else if (end - start == 2 && start[0] == '.' && start[1] == '.') 181 { 182 /* Back up to previous component, ignore if at root already. */ 183 if (dest > rpath + 1) 184 while ((--dest)[-1] != '/'); 185 } 186 else 187 { 188 size_t new_size; 189 190 if (dest[-1] != '/') 191 *dest++ = '/'; 192 193 if (dest + (end - start) >= rpath_limit) 194 { 195 ptrdiff_t dest_offset = dest - rpath; 196 char *new_rpath; 197 198 if (resolved) 199 { 200 __set_errno (ENAMETOOLONG); 201 if (dest > rpath + 1) 202 dest--; 203 *dest = '\0'; 204 goto error; 205 } 206 new_size = rpath_limit - rpath; 207 if (end - start + 1 > path_max) 208 new_size += end - start + 1; 209 else 210 new_size += path_max; 211 new_rpath = (char *) realloc (rpath, new_size); 212 if (new_rpath == NULL) 213 goto error; 214 rpath = new_rpath; 215 rpath_limit = rpath + new_size; 216 217 dest = rpath + dest_offset; 218 } 219 220 #ifdef _LIBC 221 dest = __mempcpy (dest, start, end - start); 222 #else 223 memcpy (dest, start, end - start); 224 dest += end - start; 225 #endif 226 *dest = '\0'; 227 228 #ifdef _LIBC 229 if (__lxstat64 (_STAT_VER, rpath, &st) < 0) 230 #else 231 if (lstat (rpath, &st) < 0) 232 #endif 233 goto error; 234 235 #ifdef S_ISLNK 236 if (S_ISLNK (st.st_mode)) 237 { 238 char *buf; 239 size_t len; 240 int n; 241 242 if (++num_links > MAXSYMLINKS) 243 { 244 __set_errno (ELOOP); 245 goto error; 246 } 247 248 buf = allocsa (path_max); 249 if (!buf) 250 { 251 errno = ENOMEM; 252 goto error; 253 } 254 255 n = __readlink (rpath, buf, path_max); 256 if (n < 0) 257 { 258 int saved_errno = errno; 259 freesa (buf); 260 errno = saved_errno; 261 goto error; 262 } 263 buf[n] = '\0'; 264 265 if (!extra_buf) 266 { 267 extra_buf = allocsa (path_max); 268 if (!extra_buf) 269 { 270 freesa (buf); 271 errno = ENOMEM; 272 goto error; 273 } 274 } 275 276 len = strlen (end); 277 if ((long int) (n + len) >= path_max) 278 { 279 freesa (buf); 280 __set_errno (ENAMETOOLONG); 281 goto error; 282 } 283 284 /* Careful here, end may be a pointer into extra_buf... */ 285 memmove (&extra_buf[n], end, len + 1); 286 name = end = memcpy (extra_buf, buf, n); 287 288 if (buf[0] == '/') 289 dest = rpath + 1; /* It's an absolute symlink */ 290 else 291 /* Back up to previous component, ignore if at root already: */ 292 if (dest > rpath + 1) 293 while ((--dest)[-1] != '/'); 294 } 295 #endif 296 } 297 } 298 if (dest > rpath + 1 && dest[-1] == '/') 299 --dest; 300 *dest = '\0'; 301 302 if (extra_buf) 303 freesa (extra_buf); 304 305 return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; 306 307 error: 308 { 309 int saved_errno = errno; 310 if (extra_buf) 311 freesa (extra_buf); 312 if (resolved) 313 strcpy (resolved, rpath); 314 else 315 free (rpath); 316 errno = saved_errno; 317 } 318 return NULL; 319 } 320 #ifdef _LIBC 321 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); 322 #endif 323 324 325 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) 326 char * 327 __old_realpath (const char *name, char *resolved) 328 { 329 if (resolved == NULL) 330 { 331 __set_errno (EINVAL); 332 return NULL; 333 } 334 335 return __realpath (name, resolved); 336 } 337 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0); 338 #endif 339 340 341 char * 342 __canonicalize_file_name (const char *name) 343 { 344 return __realpath (name, NULL); 345 } 346 weak_alias (__canonicalize_file_name, canonicalize_file_name) 347 348 #else 349 350 /* This declaration is solely to ensure that after preprocessing 351 this file is never empty. */ 352 typedef int dummy; 353 354 #endif 355