Annotation of embedaddon/libiconv/srclib/areadlink.c, revision 1.1
1.1 ! misho 1: /* areadlink.c -- readlink wrapper to return the link name in malloc'd storage
! 2: Unlike xreadlink and xreadlink_with_size, don't ever call exit.
! 3:
! 4: Copyright (C) 2001, 2003-2007 Free Software Foundation, Inc.
! 5:
! 6: This program is free software: you can redistribute it and/or modify
! 7: it under the terms of the GNU General Public License as published by
! 8: the Free Software Foundation; either version 3 of the License, or
! 9: (at your option) any later version.
! 10:
! 11: This program is distributed in the hope that it will be useful,
! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 14: GNU General Public License for more details.
! 15:
! 16: You should have received a copy of the GNU General Public License
! 17: along with this program. If not, see <http://www.gnu.org/licenses/>. */
! 18:
! 19: /* Written by Jim Meyering <jim@meyering.net>
! 20: and Bruno Haible <bruno@clisp.org>. */
! 21:
! 22: #include <config.h>
! 23:
! 24: /* Specification. */
! 25: #include "areadlink.h"
! 26:
! 27: #include <string.h>
! 28: #include <errno.h>
! 29: #include <limits.h>
! 30: #include <sys/types.h>
! 31: #include <stdlib.h>
! 32: #include <unistd.h>
! 33:
! 34: #ifndef SIZE_MAX
! 35: # define SIZE_MAX ((size_t) -1)
! 36: #endif
! 37: #ifndef SSIZE_MAX
! 38: # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
! 39: #endif
! 40:
! 41: /* Call readlink to get the symbolic link value of FILENAME.
! 42: Return a pointer to that NUL-terminated string in malloc'd storage.
! 43: If readlink fails, return NULL and set errno.
! 44: If realloc fails, or if the link value is longer than SIZE_MAX :-),
! 45: return NULL and set errno to ENOMEM. */
! 46:
! 47: char *
! 48: areadlink (char const *filename)
! 49: {
! 50: /* The initial buffer size for the link value. A power of 2
! 51: detects arithmetic overflow earlier, but is not required. */
! 52: #define INITIAL_BUF_SIZE 1024
! 53:
! 54: /* Allocate the initial buffer on the stack. This way, in the common
! 55: case of a symlink of small size, we get away with a single small malloc()
! 56: instead of a big malloc() followed by a shrinking realloc(). */
! 57: char initial_buf[INITIAL_BUF_SIZE];
! 58:
! 59: char *buffer = initial_buf;
! 60: size_t buf_size = sizeof (initial_buf);
! 61:
! 62: while (1)
! 63: {
! 64: /* Attempt to read the link into the current buffer. */
! 65: ssize_t link_length = readlink (filename, buffer, buf_size);
! 66:
! 67: /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
! 68: with errno == ERANGE if the buffer is too small. */
! 69: if (link_length < 0 && errno != ERANGE)
! 70: {
! 71: if (buffer != initial_buf)
! 72: {
! 73: int saved_errno = errno;
! 74: free (buffer);
! 75: errno = saved_errno;
! 76: }
! 77: return NULL;
! 78: }
! 79:
! 80: if ((size_t) link_length < buf_size)
! 81: {
! 82: buffer[link_length++] = '\0';
! 83:
! 84: /* Return it in a chunk of memory as small as possible. */
! 85: if (buffer == initial_buf)
! 86: {
! 87: buffer = (char *) malloc (link_length);
! 88: if (buffer == NULL)
! 89: /* errno is ENOMEM. */
! 90: return NULL;
! 91: memcpy (buffer, initial_buf, link_length);
! 92: }
! 93: else
! 94: {
! 95: /* Shrink buffer before returning it. */
! 96: if ((size_t) link_length < buf_size)
! 97: {
! 98: char *smaller_buffer = (char *) realloc (buffer, link_length);
! 99:
! 100: if (smaller_buffer != NULL)
! 101: buffer = smaller_buffer;
! 102: }
! 103: }
! 104: return buffer;
! 105: }
! 106:
! 107: if (buffer != initial_buf)
! 108: free (buffer);
! 109: buf_size *= 2;
! 110: if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0))
! 111: {
! 112: errno = ENOMEM;
! 113: return NULL;
! 114: }
! 115: buffer = (char *) malloc (buf_size);
! 116: if (buffer == NULL)
! 117: /* errno is ENOMEM. */
! 118: return NULL;
! 119: }
! 120: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>