1/* Return the canonical absolute name of a given file. 2 Copyright (C) 1996-2011 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#ifndef _LIBC 19# define _GL_USE_STDLIB_ALLOC 1 20# include <config.h> 21#endif 22 23#if !HAVE_CANONICALIZE_FILE_NAME || !FUNC_REALPATH_WORKS || defined _LIBC 24 25/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc 26 optimizes away the name == NULL test below. */ 27#define _GL_ARG_NONNULL(params) 28 29/* Specification. */ 30#include <stdlib.h> 31 32#include <alloca.h> 33#include <string.h> 34#include <unistd.h> 35#include <limits.h> 36#if HAVE_SYS_PARAM_H || defined _LIBC 37# include <sys/param.h> 38#endif 39#include <sys/stat.h> 40#include <errno.h> 41#include <stddef.h> 42 43#ifdef _LIBC 44# include <shlib-compat.h> 45#else 46# define SHLIB_COMPAT(lib, introduced, obsoleted) 0 47# define versioned_symbol(lib, local, symbol, version) extern int dummy 48# define compat_symbol(lib, local, symbol, version) 49# define weak_alias(local, symbol) 50# define __canonicalize_file_name canonicalize_file_name 51# define __realpath realpath 52# include "pathmax.h" 53# include "malloca.h" 54# if HAVE_GETCWD 55# if IN_RELOCWRAPPER 56 /* When building the relocatable program wrapper, use the system's getcwd 57 function, not the gnulib override, otherwise we would get a link error. 58 */ 59# undef getcwd 60# endif 61# ifdef VMS 62 /* We want the directory in Unix syntax, not in VMS syntax. */ 63# define __getcwd(buf, max) getcwd (buf, max, 0) 64# else 65# define __getcwd getcwd 66# endif 67# else 68# define __getcwd(buf, max) getwd (buf) 69# endif 70# define __readlink readlink 71# define __set_errno(e) errno = (e) 72# ifndef MAXSYMLINKS 73# ifdef SYMLOOP_MAX 74# define MAXSYMLINKS SYMLOOP_MAX 75# else 76# define MAXSYMLINKS 20 77# endif 78# endif 79#endif 80 81#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT 82# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 83#endif 84 85#if !FUNC_REALPATH_WORKS || defined _LIBC 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 int num_links = 0; 104 105 if (name == NULL) 106 { 107 /* As per Single Unix Specification V2 we must return an error if 108 either parameter is a null pointer. We extend this to allow 109 the RESOLVED parameter to be NULL in case the we are expected to 110 allocate the room for the return value. */ 111 __set_errno (EINVAL); 112 return NULL; 113 } 114 115 if (name[0] == '\0') 116 { 117 /* As per Single Unix Specification V2 we must return an error if 118 the name argument points to an empty string. */ 119 __set_errno (ENOENT); 120 return NULL; 121 } 122 123#ifdef PATH_MAX 124 path_max = PATH_MAX; 125#else 126 path_max = pathconf (name, _PC_PATH_MAX); 127 if (path_max <= 0) 128 path_max = 8192; 129#endif 130 131 if (resolved == NULL) 132 { 133 rpath = malloc (path_max); 134 if (rpath == NULL) 135 { 136 /* It's easier to set errno to ENOMEM than to rely on the 137 'malloc-posix' gnulib module. */ 138 errno = ENOMEM; 139 return NULL; 140 } 141 } 142 else 143 rpath = resolved; 144 rpath_limit = rpath + path_max; 145 146 if (name[0] != '/') 147 { 148 if (!__getcwd (rpath, path_max)) 149 { 150 rpath[0] = '\0'; 151 goto error; 152 } 153 dest = strchr (rpath, '\0'); 154 } 155 else 156 { 157 rpath[0] = '/'; 158 dest = rpath + 1; 159 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/') 160 *dest++ = '/'; 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 int n; 171 172 /* Skip sequence of multiple path-separators. */ 173 while (*start == '/') 174 ++start; 175 176 /* Find end of path component. */ 177 for (end = start; *end && *end != '/'; ++end) 178 /* Nothing. */; 179 180 if (end - start == 0) 181 break; 182 else if (end - start == 1 && start[0] == '.') 183 /* nothing */; 184 else if (end - start == 2 && start[0] == '.' && start[1] == '.') 185 { 186 /* Back up to previous component, ignore if at root already. */ 187 if (dest > rpath + 1) 188 while ((--dest)[-1] != '/'); 189 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 190 && *dest == '/') 191 dest++; 192 } 193 else 194 { 195 size_t new_size; 196 197 if (dest[-1] != '/') 198 *dest++ = '/'; 199 200 if (dest + (end - start) >= rpath_limit) 201 { 202 ptrdiff_t dest_offset = dest - rpath; 203 char *new_rpath; 204 205 if (resolved) 206 { 207 __set_errno (ENAMETOOLONG); 208 if (dest > rpath + 1) 209 dest--; 210 *dest = '\0'; 211 goto error; 212 } 213 new_size = rpath_limit - rpath; 214 if (end - start + 1 > path_max) 215 new_size += end - start + 1; 216 else 217 new_size += path_max; 218 new_rpath = (char *) realloc (rpath, new_size); 219 if (new_rpath == NULL) 220 { 221 /* It's easier to set errno to ENOMEM than to rely on the 222 'realloc-posix' gnulib module. */ 223 errno = ENOMEM; 224 goto error; 225 } 226 rpath = new_rpath; 227 rpath_limit = rpath + new_size; 228 229 dest = rpath + dest_offset; 230 } 231 232#ifdef _LIBC 233 dest = __mempcpy (dest, start, end - start); 234#else 235 memcpy (dest, start, end - start); 236 dest += end - start; 237#endif 238 *dest = '\0'; 239 240#ifdef _LIBC 241 if (__lxstat64 (_STAT_VER, rpath, &st) < 0) 242#else 243 if (lstat (rpath, &st) < 0) 244#endif 245 goto error; 246 247 if (S_ISLNK (st.st_mode)) 248 { 249 char *buf; 250 size_t len; 251 252 if (++num_links > MAXSYMLINKS) 253 { 254 __set_errno (ELOOP); 255 goto error; 256 } 257 258 buf = malloca (path_max); 259 if (!buf) 260 { 261 errno = ENOMEM; 262 goto error; 263 } 264 265 n = __readlink (rpath, buf, path_max - 1); 266 if (n < 0) 267 { 268 int saved_errno = errno; 269 freea (buf); 270 errno = saved_errno; 271 goto error; 272 } 273 buf[n] = '\0'; 274 275 if (!extra_buf) 276 { 277 extra_buf = malloca (path_max); 278 if (!extra_buf) 279 { 280 freea (buf); 281 errno = ENOMEM; 282 goto error; 283 } 284 } 285 286 len = strlen (end); 287 if ((long int) (n + len) >= path_max) 288 { 289 freea (buf); 290 __set_errno (ENAMETOOLONG); 291 goto error; 292 } 293 294 /* Careful here, end may be a pointer into extra_buf... */ 295 memmove (&extra_buf[n], end, len + 1); 296 name = end = memcpy (extra_buf, buf, n); 297 298 if (buf[0] == '/') 299 { 300 dest = rpath + 1; /* It's an absolute symlink */ 301 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/') 302 *dest++ = '/'; 303 } 304 else 305 { 306 /* Back up to previous component, ignore if at root 307 already: */ 308 if (dest > rpath + 1) 309 while ((--dest)[-1] != '/'); 310 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 311 && *dest == '/') 312 dest++; 313 } 314 } 315 else if (!S_ISDIR (st.st_mode) && *end != '\0') 316 { 317 __set_errno (ENOTDIR); 318 goto error; 319 } 320 } 321 } 322 if (dest > rpath + 1 && dest[-1] == '/') 323 --dest; 324 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && *dest == '/') 325 dest++; 326 *dest = '\0'; 327 328 if (extra_buf) 329 freea (extra_buf); 330 331 return rpath; 332 333error: 334 { 335 int saved_errno = errno; 336 if (extra_buf) 337 freea (extra_buf); 338 if (resolved == NULL) 339 free (rpath); 340 errno = saved_errno; 341 } 342 return NULL; 343} 344versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); 345#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */ 346 347 348#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) 349char * 350attribute_compat_text_section 351__old_realpath (const char *name, char *resolved) 352{ 353 if (resolved == NULL) 354 { 355 __set_errno (EINVAL); 356 return NULL; 357 } 358 359 return __realpath (name, resolved); 360} 361compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0); 362#endif 363 364 365char * 366__canonicalize_file_name (const char *name) 367{ 368 return __realpath (name, NULL); 369} 370weak_alias (__canonicalize_file_name, canonicalize_file_name) 371 372#else 373 374/* This declaration is solely to ensure that after preprocessing 375 this file is never empty. */ 376typedef int dummy; 377 378#endif 379