1 /* Return the canonical absolute name of a given file. 2 Copyright (C) 1996-2020 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 <https://www.gnu.org/licenses/>. */ 17 18 #ifndef _LIBC 19 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc 20 optimizes away the name == NULL test below. */ 21 # define _GL_ARG_NONNULL(params) 22 23 # define _GL_USE_STDLIB_ALLOC 1 24 # include <config.h> 25 #endif 26 27 #if !HAVE_CANONICALIZE_FILE_NAME || !FUNC_REALPATH_WORKS || defined _LIBC 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 # include "filename.h" 55 # if HAVE_GETCWD 56 # if IN_RELOCWRAPPER 57 /* When building the relocatable program wrapper, use the system's getcwd 58 function, not the gnulib override, otherwise we would get a link error. 59 */ 60 # undef getcwd 61 # endif 62 # if defined VMS && !defined getcwd 63 /* We want the directory in Unix syntax, not in VMS syntax. 64 The gnulib override of 'getcwd' takes 2 arguments; the original VMS 65 'getcwd' takes 3 arguments. */ 66 # define __getcwd(buf, max) getcwd (buf, max, 0) 67 # else 68 # define __getcwd getcwd 69 # endif 70 # else 71 # define __getcwd(buf, max) getwd (buf) 72 # endif 73 # define __readlink readlink 74 # define __set_errno(e) errno = (e) 75 # ifndef MAXSYMLINKS 76 # ifdef SYMLOOP_MAX 77 # define MAXSYMLINKS SYMLOOP_MAX 78 # else 79 # define MAXSYMLINKS 20 80 # endif 81 # endif 82 #endif 83 84 #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT 85 # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 86 #endif 87 88 /* Define this independently so that stdint.h is not a prerequisite. */ 89 #ifndef SIZE_MAX 90 # define SIZE_MAX ((size_t) -1) 91 #endif 92 93 #if !FUNC_REALPATH_WORKS || defined _LIBC 94 95 static void 96 alloc_failed (void) 97 { 98 #if defined _WIN32 && ! defined __CYGWIN__ 99 /* Avoid errno problem without using the malloc or realloc modules; see: 100 https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html */ 101 errno = ENOMEM; 102 #endif 103 } 104 105 /* Return the canonical absolute name of file NAME. A canonical name 106 does not contain any ".", ".." components nor any repeated path 107 separators ('/') or symlinks. All path components must exist. If 108 RESOLVED is null, the result is malloc'd; otherwise, if the 109 canonical name is PATH_MAX chars or more, returns null with 'errno' 110 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, 111 returns the name in RESOLVED. If the name cannot be resolved and 112 RESOLVED is non-NULL, it contains the path of the first component 113 that cannot be resolved. If the path can be resolved, RESOLVED 114 holds the same value as the value returned. */ 115 116 char * 117 __realpath (const char *name, char *resolved) 118 { 119 char *rpath, *dest, *extra_buf = NULL; 120 const char *start, *end, *rpath_limit; 121 long int path_max; 122 int num_links = 0; 123 size_t prefix_len; 124 125 if (name == NULL) 126 { 127 /* As per Single Unix Specification V2 we must return an error if 128 either parameter is a null pointer. We extend this to allow 129 the RESOLVED parameter to be NULL in case the we are expected to 130 allocate the room for the return value. */ 131 __set_errno (EINVAL); 132 return NULL; 133 } 134 135 if (name[0] == '\0') 136 { 137 /* As per Single Unix Specification V2 we must return an error if 138 the name argument points to an empty string. */ 139 __set_errno (ENOENT); 140 return NULL; 141 } 142 143 #ifdef PATH_MAX 144 path_max = PATH_MAX; 145 #else 146 path_max = pathconf (name, _PC_PATH_MAX); 147 if (path_max <= 0) 148 path_max = 8192; 149 #endif 150 151 if (resolved == NULL) 152 { 153 rpath = malloc (path_max); 154 if (rpath == NULL) 155 { 156 alloc_failed (); 157 return NULL; 158 } 159 } 160 else 161 rpath = resolved; 162 rpath_limit = rpath + path_max; 163 164 /* This is always zero for Posix hosts, but can be 2 for MS-Windows 165 and MS-DOS X:/foo/bar file names. */ 166 prefix_len = FILE_SYSTEM_PREFIX_LEN (name); 167 168 if (!IS_ABSOLUTE_FILE_NAME (name)) 169 { 170 if (!__getcwd (rpath, path_max)) 171 { 172 rpath[0] = '\0'; 173 goto error; 174 } 175 dest = strchr (rpath, '\0'); 176 start = name; 177 prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath); 178 } 179 else 180 { 181 dest = rpath; 182 if (prefix_len) 183 { 184 memcpy (rpath, name, prefix_len); 185 dest += prefix_len; 186 } 187 *dest++ = '/'; 188 if (DOUBLE_SLASH_IS_DISTINCT_ROOT) 189 { 190 if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len) 191 *dest++ = '/'; 192 *dest = '\0'; 193 } 194 start = name + prefix_len; 195 } 196 197 for (end = start; *start; start = end) 198 { 199 #ifdef _LIBC 200 struct stat64 st; 201 #else 202 struct stat st; 203 #endif 204 205 /* Skip sequence of multiple path-separators. */ 206 while (ISSLASH (*start)) 207 ++start; 208 209 /* Find end of path component. */ 210 for (end = start; *end && !ISSLASH (*end); ++end) 211 /* Nothing. */; 212 213 if (end - start == 0) 214 break; 215 else if (end - start == 1 && start[0] == '.') 216 /* nothing */; 217 else if (end - start == 2 && start[0] == '.' && start[1] == '.') 218 { 219 /* Back up to previous component, ignore if at root already. */ 220 if (dest > rpath + prefix_len + 1) 221 for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) 222 continue; 223 if (DOUBLE_SLASH_IS_DISTINCT_ROOT 224 && dest == rpath + 1 && !prefix_len 225 && ISSLASH (*dest) && !ISSLASH (dest[1])) 226 dest++; 227 } 228 else 229 { 230 size_t new_size; 231 232 if (!ISSLASH (dest[-1])) 233 *dest++ = '/'; 234 235 if (dest + (end - start) >= rpath_limit) 236 { 237 ptrdiff_t dest_offset = dest - rpath; 238 char *new_rpath; 239 240 if (resolved) 241 { 242 __set_errno (ENAMETOOLONG); 243 if (dest > rpath + prefix_len + 1) 244 dest--; 245 *dest = '\0'; 246 goto error; 247 } 248 new_size = rpath_limit - rpath; 249 if (end - start + 1 > path_max) 250 new_size += end - start + 1; 251 else 252 new_size += path_max; 253 new_rpath = (char *) realloc (rpath, new_size); 254 if (new_rpath == NULL) 255 { 256 alloc_failed (); 257 goto error; 258 } 259 rpath = new_rpath; 260 rpath_limit = rpath + new_size; 261 262 dest = rpath + dest_offset; 263 } 264 265 #ifdef _LIBC 266 dest = __mempcpy (dest, start, end - start); 267 #else 268 memcpy (dest, start, end - start); 269 dest += end - start; 270 #endif 271 *dest = '\0'; 272 273 /* FIXME: if lstat fails with errno == EOVERFLOW, 274 the entry exists. */ 275 #ifdef _LIBC 276 if (__lxstat64 (_STAT_VER, rpath, &st) < 0) 277 #else 278 if (lstat (rpath, &st) < 0) 279 #endif 280 goto error; 281 282 if (S_ISLNK (st.st_mode)) 283 { 284 char *buf; 285 size_t len; 286 ssize_t n; 287 288 if (++num_links > MAXSYMLINKS) 289 { 290 __set_errno (ELOOP); 291 goto error; 292 } 293 294 buf = malloca (path_max); 295 if (!buf) 296 { 297 __set_errno (ENOMEM); 298 goto error; 299 } 300 301 n = __readlink (rpath, buf, path_max - 1); 302 if (n < 0) 303 { 304 int saved_errno = errno; 305 freea (buf); 306 __set_errno (saved_errno); 307 goto error; 308 } 309 buf[n] = '\0'; 310 311 if (!extra_buf) 312 { 313 extra_buf = malloca (path_max); 314 if (!extra_buf) 315 { 316 freea (buf); 317 __set_errno (ENOMEM); 318 goto error; 319 } 320 } 321 322 len = strlen (end); 323 /* Check that n + len + 1 doesn't overflow and is <= path_max. */ 324 if (n >= SIZE_MAX - len || n + len >= path_max) 325 { 326 freea (buf); 327 __set_errno (ENAMETOOLONG); 328 goto error; 329 } 330 331 /* Careful here, end may be a pointer into extra_buf... */ 332 memmove (&extra_buf[n], end, len + 1); 333 name = end = memcpy (extra_buf, buf, n); 334 335 if (IS_ABSOLUTE_FILE_NAME (buf)) 336 { 337 size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); 338 339 if (pfxlen) 340 memcpy (rpath, buf, pfxlen); 341 dest = rpath + pfxlen; 342 *dest++ = '/'; /* It's an absolute symlink */ 343 if (DOUBLE_SLASH_IS_DISTINCT_ROOT) 344 { 345 if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen) 346 *dest++ = '/'; 347 *dest = '\0'; 348 } 349 /* Install the new prefix to be in effect hereafter. */ 350 prefix_len = pfxlen; 351 } 352 else 353 { 354 /* Back up to previous component, ignore if at root 355 already: */ 356 if (dest > rpath + prefix_len + 1) 357 for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) 358 continue; 359 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 360 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) 361 dest++; 362 } 363 } 364 else if (!S_ISDIR (st.st_mode) && *end != '\0') 365 { 366 __set_errno (ENOTDIR); 367 goto error; 368 } 369 } 370 } 371 if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1])) 372 --dest; 373 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len 374 && ISSLASH (*dest) && !ISSLASH (dest[1])) 375 dest++; 376 *dest = '\0'; 377 378 if (extra_buf) 379 freea (extra_buf); 380 381 return rpath; 382 383 error: 384 { 385 int saved_errno = errno; 386 if (extra_buf) 387 freea (extra_buf); 388 if (resolved == NULL) 389 free (rpath); 390 __set_errno (saved_errno); 391 } 392 return NULL; 393 } 394 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); 395 #endif /* !FUNC_REALPATH_WORKS || defined _LIBC */ 396 397 398 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) 399 char * 400 attribute_compat_text_section 401 __old_realpath (const char *name, char *resolved) 402 { 403 if (resolved == NULL) 404 { 405 __set_errno (EINVAL); 406 return NULL; 407 } 408 409 return __realpath (name, resolved); 410 } 411 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0); 412 #endif 413 414 415 char * 416 __canonicalize_file_name (const char *name) 417 { 418 return __realpath (name, NULL); 419 } 420 weak_alias (__canonicalize_file_name, canonicalize_file_name) 421 422 #else 423 424 /* This declaration is solely to ensure that after preprocessing 425 this file is never empty. */ 426 typedef int dummy; 427 428 #endif 429