Annotation of embedaddon/libiconv/srclib/canonicalize-lgpl.c, revision 1.1
1.1 ! misho 1: /* Return the canonical absolute name of a given file.
! 2: Copyright (C) 1996-2003, 2005-2008 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_ISLNK && !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:
! 97: char *
! 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 - 1);
! 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:
! 315: error:
! 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
! 329: versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
! 330: #endif
! 331:
! 332:
! 333: #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
! 334: char *
! 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: }
! 345: compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
! 346: #endif
! 347:
! 348:
! 349: char *
! 350: __canonicalize_file_name (const char *name)
! 351: {
! 352: return __realpath (name, NULL);
! 353: }
! 354: weak_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. */
! 360: typedef int dummy;
! 361:
! 362: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>