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