This source file includes following definitions.
- readlink_stk
- careadlinkat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <config.h>
22
23 #include "careadlinkat.h"
24
25 #include "idx.h"
26 #include "minmax.h"
27
28 #include <errno.h>
29 #include <limits.h>
30 #include <string.h>
31 #include <unistd.h>
32
33
34 #ifndef SIZE_MAX
35 # define SIZE_MAX ((size_t) -1)
36 #endif
37
38 #ifndef SSIZE_MAX
39 # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
40 #endif
41
42 #include "allocator.h"
43
44 enum { STACK_BUF_SIZE = 1024 };
45
46
47
48
49
50
51
52
53
54
55
56
57 #if _GL_GNUC_PREREQ (10, 1)
58 # if defined GCC_LINT || defined lint
59 __attribute__ ((__noinline__))
60 # elif __OPTIMIZE__ && !__NO_INLINE__
61 # define GCC_BOGUS_WRETURN_LOCAL_ADDR
62 # endif
63 #endif
64 static char *
65 readlink_stk (int fd, char const *filename,
66 char *buffer, size_t buffer_size,
67 struct allocator const *alloc,
68 ssize_t (*preadlinkat) (int, char const *, char *, size_t),
69 char stack_buf[STACK_BUF_SIZE])
70 {
71 if (! alloc)
72 alloc = &stdlib_allocator;
73
74 if (!buffer)
75 {
76 buffer = stack_buf;
77 buffer_size = STACK_BUF_SIZE;
78 }
79
80 char *buf = buffer;
81 idx_t buf_size_max = MIN (IDX_MAX, MIN (SSIZE_MAX, SIZE_MAX));
82 idx_t buf_size = MIN (buffer_size, buf_size_max);
83
84 while (buf)
85 {
86
87 idx_t link_length = preadlinkat (fd, filename, buf, buf_size);
88 if (link_length < 0)
89 {
90 if (buf != buffer)
91 {
92 int readlinkat_errno = errno;
93 alloc->free (buf);
94 errno = readlinkat_errno;
95 }
96 return NULL;
97 }
98
99 idx_t link_size = link_length;
100
101 if (link_size < buf_size)
102 {
103 buf[link_size++] = '\0';
104
105 if (buf == stack_buf)
106 {
107 char *b = alloc->allocate (link_size);
108 buf_size = link_size;
109 if (! b)
110 break;
111 return memcpy (b, buf, link_size);
112 }
113
114 if (link_size < buf_size && buf != buffer && alloc->reallocate)
115 {
116
117 char *b = alloc->reallocate (buf, link_size);
118 if (b)
119 return b;
120 }
121
122 return buf;
123 }
124
125 if (buf != buffer)
126 alloc->free (buf);
127
128 if (buf_size_max / 2 <= buf_size)
129 {
130 errno = ENAMETOOLONG;
131 return NULL;
132 }
133
134 buf_size = 2 * buf_size + 1;
135 buf = alloc->allocate (buf_size);
136 }
137
138 if (alloc->die)
139 alloc->die (buf_size);
140 errno = ENOMEM;
141 return NULL;
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 char *
168 careadlinkat (int fd, char const *filename,
169 char *buffer, size_t buffer_size,
170 struct allocator const *alloc,
171 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
172 {
173
174
175
176
177 #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
178 #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
179 #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
180 #endif
181 char stack_buf[STACK_BUF_SIZE];
182 return readlink_stk (fd, filename, buffer, buffer_size, alloc,
183 preadlinkat, stack_buf);
184 }