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 99char * 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 307error: 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 321versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); 322#endif 323 324 325#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) 326char * 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} 337compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0); 338#endif 339 340 341char * 342__canonicalize_file_name (const char *name) 343{ 344 return __realpath (name, NULL); 345} 346weak_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. */ 352typedef int dummy; 353 354#endif 355