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