This source file includes following definitions.
- file_accessible
 
- suffix_requires_dir_check
 
- dir_check
 
- get_path_max
 
- realpath_stk
 
- __realpath
 
- libc_hidden_def
 
- __canonicalize_file_name
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 #ifndef _LIBC
  20 
  21 
  22 # define _GL_ARG_NONNULL(params)
  23 
  24 # include <libc-config.h>
  25 #endif
  26 
  27 
  28 #include <stdlib.h>
  29 
  30 #include <errno.h>
  31 #include <fcntl.h>
  32 #include <limits.h>
  33 #include <stdbool.h>
  34 #include <string.h>
  35 #include <sys/stat.h>
  36 #include <unistd.h>
  37 
  38 #include <eloop-threshold.h>
  39 #include <filename.h>
  40 #include <idx.h>
  41 #include <intprops.h>
  42 #include <scratch_buffer.h>
  43 
  44 #ifdef _LIBC
  45 # include <shlib-compat.h>
  46 # define GCC_LINT 1
  47 # define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
  48 #else
  49 # define __canonicalize_file_name canonicalize_file_name
  50 # define __realpath realpath
  51 # include "pathmax.h"
  52 # define __faccessat faccessat
  53 # if defined _WIN32 && !defined __CYGWIN__
  54 #  define __getcwd _getcwd
  55 # elif HAVE_GETCWD
  56 #  if IN_RELOCWRAPPER
  57     
  58 
  59 
  60 #   undef getcwd
  61 #  endif
  62 #  if defined VMS && !defined getcwd
  63     
  64 
  65 
  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 __mempcpy mempcpy
  74 # define __pathconf pathconf
  75 # define __rawmemchr rawmemchr
  76 # define __readlink readlink
  77 # if IN_RELOCWRAPPER
  78     
  79 
  80 
  81 #  undef memmove
  82 # endif
  83 #endif
  84 
  85 
  86 #if defined GCC_LINT || defined lint
  87 # define IF_LINT(Code) Code
  88 #else
  89 # define IF_LINT(Code) 
  90 #endif
  91 
  92 #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
  93 # define DOUBLE_SLASH_IS_DISTINCT_ROOT false
  94 #endif
  95 
  96 #if defined _LIBC || !FUNC_REALPATH_WORKS
  97 
  98 
  99 
 100 static bool
 101 file_accessible (char const *file)
     
 102 {
 103 # if defined _LIBC || HAVE_FACCESSAT
 104   return __faccessat (AT_FDCWD, file, F_OK, AT_EACCESS) == 0;
 105 # else
 106   struct stat st;
 107   return stat (file, &st) == 0 || errno == EOVERFLOW;
 108 # endif
 109 }
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 static bool _GL_ATTRIBUTE_PURE
 119 suffix_requires_dir_check (char const *end)
     
 120 {
 121   
 122   while (ISSLASH (*end))
 123     {
 124       
 125       do
 126         end++;
 127       while (ISSLASH (*end));
 128 
 129       switch (*end++)
 130         {
 131         default: return false;  
 132         case '\0': return true; 
 133         case '.': break;        
 134         }
 135       
 136       if (!*end || (*end == '.' && (!end[1] || ISSLASH (end[1]))))
 137         return true;
 138     }
 139 
 140   return false;
 141 }
 142 
 143 
 144 
 145 
 146 
 147 
 148 # if defined _LIBC || defined LSTAT_FOLLOWS_SLASHED_SYMLINK
 149 static char const dir_suffix[] = "/";
 150 # else
 151 static char const dir_suffix[] = "/./";
 152 # endif
 153 
 154 
 155 
 156 
 157 
 158 static bool
 159 dir_check (char *dir, char *dirend)
     
 160 {
 161   strcpy (dirend, dir_suffix);
 162   return file_accessible (dir);
 163 }
 164 
 165 static idx_t
 166 get_path_max (void)
     
 167 {
 168 # ifdef PATH_MAX
 169   long int path_max = PATH_MAX;
 170 # else
 171   
 172 
 173 
 174 
 175 
 176   int err = errno;
 177   long int path_max = __pathconf ("/", _PC_PATH_MAX);
 178   __set_errno (err);
 179 # endif
 180   return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX;
 181 }
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 
 191 
 192 
 193 
 194 # if __GNUC_PREREQ (10, 1)
 195 #  if defined GCC_LINT || defined lint
 196 __attribute__ ((__noinline__))
 197 #  elif __OPTIMIZE__ && !__NO_INLINE__
 198 #   define GCC_BOGUS_WRETURN_LOCAL_ADDR
 199 #  endif
 200 # endif
 201 static char *
 202 realpath_stk (const char *name, char *resolved,
     
 203               struct scratch_buffer *rname_buf)
 204 {
 205   char *dest;
 206   char const *start;
 207   char const *end;
 208   int num_links = 0;
 209 
 210   if (name == NULL)
 211     {
 212       
 213 
 214 
 215 
 216       __set_errno (EINVAL);
 217       return NULL;
 218     }
 219 
 220   if (name[0] == '\0')
 221     {
 222       
 223 
 224       __set_errno (ENOENT);
 225       return NULL;
 226     }
 227 
 228   struct scratch_buffer extra_buffer, link_buffer;
 229   scratch_buffer_init (&extra_buffer);
 230   scratch_buffer_init (&link_buffer);
 231   scratch_buffer_init (rname_buf);
 232   char *rname_on_stack = rname_buf->data;
 233   char *rname = rname_on_stack;
 234   bool end_in_extra_buffer = false;
 235   bool failed = true;
 236 
 237   
 238 
 239   idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
 240 
 241   if (!IS_ABSOLUTE_FILE_NAME (name))
 242     {
 243       while (!__getcwd (rname, rname_buf->length))
 244         {
 245           if (errno != ERANGE)
 246             {
 247               dest = rname;
 248               goto error;
 249             }
 250           if (!scratch_buffer_grow (rname_buf))
 251             goto error_nomem;
 252           rname = rname_buf->data;
 253         }
 254       dest = __rawmemchr (rname, '\0');
 255       start = name;
 256       prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
 257     }
 258   else
 259     {
 260       dest = __mempcpy (rname, name, prefix_len);
 261       *dest++ = '/';
 262       if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
 263         {
 264           if (prefix_len == 0 
 265               && ISSLASH (name[1]) && !ISSLASH (name[2]))
 266             *dest++ = '/';
 267           *dest = '\0';
 268         }
 269       start = name + prefix_len;
 270     }
 271 
 272   for ( ; *start; start = end)
 273     {
 274       
 275       while (ISSLASH (*start))
 276         ++start;
 277 
 278       
 279       for (end = start; *end && !ISSLASH (*end); ++end)
 280         ;
 281 
 282       
 283 
 284       idx_t startlen = end - start;
 285 
 286       if (startlen == 0)
 287         break;
 288       else if (startlen == 1 && start[0] == '.')
 289         ;
 290       else if (startlen == 2 && start[0] == '.' && start[1] == '.')
 291         {
 292           
 293           if (dest > rname + prefix_len + 1)
 294             for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
 295               continue;
 296           if (DOUBLE_SLASH_IS_DISTINCT_ROOT
 297               && dest == rname + 1 && !prefix_len
 298               && ISSLASH (*dest) && !ISSLASH (dest[1]))
 299             dest++;
 300         }
 301       else
 302         {
 303           if (!ISSLASH (dest[-1]))
 304             *dest++ = '/';
 305 
 306           while (rname + rname_buf->length - dest
 307                  < startlen + sizeof dir_suffix)
 308             {
 309               idx_t dest_offset = dest - rname;
 310               if (!scratch_buffer_grow_preserve (rname_buf))
 311                 goto error_nomem;
 312               rname = rname_buf->data;
 313               dest = rname + dest_offset;
 314             }
 315 
 316           dest = __mempcpy (dest, start, startlen);
 317           *dest = '\0';
 318 
 319           char *buf;
 320           ssize_t n;
 321           while (true)
 322             {
 323               buf = link_buffer.data;
 324               idx_t bufsize = link_buffer.length;
 325               n = __readlink (rname, buf, bufsize - 1);
 326               if (n < bufsize - 1)
 327                 break;
 328               if (!scratch_buffer_grow (&link_buffer))
 329                 goto error_nomem;
 330             }
 331           if (0 <= n)
 332             {
 333               if (++num_links > __eloop_threshold ())
 334                 {
 335                   __set_errno (ELOOP);
 336                   goto error;
 337                 }
 338 
 339               buf[n] = '\0';
 340 
 341               char *extra_buf = extra_buffer.data;
 342               idx_t end_idx IF_LINT (= 0);
 343               if (end_in_extra_buffer)
 344                 end_idx = end - extra_buf;
 345               size_t len = strlen (end);
 346               if (INT_ADD_OVERFLOW (len, n))
 347                 {
 348                   __set_errno (ENOMEM);
 349                   goto error_nomem;
 350                 }
 351               while (extra_buffer.length <= len + n)
 352                 {
 353                   if (!scratch_buffer_grow_preserve (&extra_buffer))
 354                     goto error_nomem;
 355                   extra_buf = extra_buffer.data;
 356                 }
 357               if (end_in_extra_buffer)
 358                 end = extra_buf + end_idx;
 359 
 360               
 361               memmove (&extra_buf[n], end, len + 1);
 362               name = end = memcpy (extra_buf, buf, n);
 363               end_in_extra_buffer = true;
 364 
 365               if (IS_ABSOLUTE_FILE_NAME (buf))
 366                 {
 367                   idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
 368 
 369                   dest = __mempcpy (rname, buf, pfxlen);
 370                   *dest++ = '/'; 
 371                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
 372                     {
 373                       if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
 374                         *dest++ = '/';
 375                       *dest = '\0';
 376                     }
 377                   
 378                   prefix_len = pfxlen;
 379                 }
 380               else
 381                 {
 382                   
 383 
 384                   if (dest > rname + prefix_len + 1)
 385                     for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
 386                       continue;
 387                   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
 388                       && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
 389                     dest++;
 390                 }
 391             }
 392           else if (! (suffix_requires_dir_check (end)
 393                       ? dir_check (rname, dest)
 394                       : errno == EINVAL))
 395             goto error;
 396         }
 397     }
 398   if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
 399     --dest;
 400   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
 401       && ISSLASH (*dest) && !ISSLASH (dest[1]))
 402     dest++;
 403   failed = false;
 404 
 405 error:
 406   *dest++ = '\0';
 407   if (resolved != NULL && dest - rname <= get_path_max ())
 408     rname = strcpy (resolved, rname);
 409 
 410 error_nomem:
 411   scratch_buffer_free (&extra_buffer);
 412   scratch_buffer_free (&link_buffer);
 413 
 414   if (failed || rname == resolved)
 415     {
 416       scratch_buffer_free (rname_buf);
 417       return failed ? NULL : resolved;
 418     }
 419 
 420   return scratch_buffer_dupfree (rname_buf, dest - rname);
 421 }
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 
 432 
 433 
 434 char *
 435 __realpath (const char *name, char *resolved)
     
 436 {
 437   #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
 438    #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
 439    #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
 440   #endif
 441   struct scratch_buffer rname_buffer;
 442   return realpath_stk (name, resolved, &rname_buffer);
 443 }
 444 libc_hidden_def (__realpath)
     
 445 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
 446 
 447 #endif 
 448 
 449 
 450 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
 451 char *
 452 attribute_compat_text_section
 453 __old_realpath (const char *name, char *resolved)
 454 {
 455   if (resolved == NULL)
 456     {
 457       __set_errno (EINVAL);
 458       return NULL;
 459     }
 460 
 461   return __realpath (name, resolved);
 462 }
 463 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
 464 #endif
 465 
 466 
 467 char *
 468 __canonicalize_file_name (const char *name)
     
 469 {
 470   return __realpath (name, NULL);
 471 }
 472 weak_alias (__canonicalize_file_name, canonicalize_file_name)