Annotation of embedaddon/libiconv/srclib/areadlink.c, revision 1.1.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>