Line data Source code
1 : /* membuf.c - A simple implementation of a dynamic buffer.
2 : * Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
3 : * Copyright (C) 2013 Werner Koch
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * This file is free software; you can redistribute it and/or modify
8 : * it under the terms of either
9 : *
10 : * - the GNU Lesser General Public License as published by the Free
11 : * Software Foundation; either version 3 of the License, or (at
12 : * your option) any later version.
13 : *
14 : * or
15 : *
16 : * - the GNU General Public License as published by the Free
17 : * Software Foundation; either version 2 of the License, or (at
18 : * your option) any later version.
19 : *
20 : * or both in parallel, as here.
21 : *
22 : * This file is distributed in the hope that it will be useful,
23 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 : * GNU General Public License for more details.
26 : *
27 : * You should have received a copy of the GNU General Public License
28 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : #include <config.h>
32 : #include <stdlib.h>
33 : #include <errno.h>
34 : #include <stdarg.h>
35 :
36 : #include "util.h"
37 : #include "membuf.h"
38 :
39 :
40 : /* A simple implementation of a dynamic buffer. Use init_membuf() to
41 : create a buffer, put_membuf to append bytes and get_membuf to
42 : release and return the buffer. Allocation errors are detected but
43 : only returned at the final get_membuf(), this helps not to clutter
44 : the code with out of core checks. */
45 :
46 : void
47 1027 : init_membuf (membuf_t *mb, int initiallen)
48 : {
49 1027 : mb->len = 0;
50 1027 : mb->size = initiallen;
51 1027 : mb->out_of_core = 0;
52 1027 : mb->buf = xtrymalloc (initiallen);
53 1027 : if (!mb->buf)
54 0 : mb->out_of_core = errno;
55 1027 : }
56 :
57 : /* Same as init_membuf but allocates the buffer in secure memory. */
58 : void
59 259 : init_membuf_secure (membuf_t *mb, int initiallen)
60 : {
61 259 : mb->len = 0;
62 259 : mb->size = initiallen;
63 259 : mb->out_of_core = 0;
64 259 : mb->buf = xtrymalloc_secure (initiallen);
65 259 : if (!mb->buf)
66 0 : mb->out_of_core = errno;
67 259 : }
68 :
69 :
70 : /* Shift the the content of the membuf MB by AMOUNT bytes. The next
71 : operation will then behave as if AMOUNT bytes had not been put into
72 : the buffer. If AMOUNT is greater than the actual accumulated
73 : bytes, the membuf is basically reset to its initial state. */
74 : void
75 0 : clear_membuf (membuf_t *mb, size_t amount)
76 : {
77 : /* No need to clear if we are already out of core. */
78 0 : if (mb->out_of_core)
79 0 : return;
80 0 : if (amount >= mb->len)
81 0 : mb->len = 0;
82 : else
83 : {
84 0 : mb->len -= amount;
85 0 : memmove (mb->buf, mb->buf+amount, mb->len);
86 : }
87 : }
88 :
89 :
90 : void
91 3336 : put_membuf (membuf_t *mb, const void *buf, size_t len)
92 : {
93 3336 : if (mb->out_of_core || !len)
94 33 : return;
95 :
96 3303 : if (mb->len + len >= mb->size)
97 : {
98 : char *p;
99 :
100 0 : mb->size += len + 1024;
101 0 : p = xtryrealloc (mb->buf, mb->size);
102 0 : if (!p)
103 : {
104 0 : mb->out_of_core = errno ? errno : ENOMEM;
105 : /* Wipe out what we already accumulated. This is required
106 : in case we are storing sensitive data here. The membuf
107 : API does not provide another way to cleanup after an
108 : error. */
109 0 : wipememory (mb->buf, mb->len);
110 0 : return;
111 : }
112 0 : mb->buf = p;
113 : }
114 3303 : memcpy (mb->buf + mb->len, buf, len);
115 3303 : mb->len += len;
116 : }
117 :
118 :
119 : void
120 1672 : put_membuf_str (membuf_t *mb, const char *string)
121 : {
122 1672 : put_membuf (mb, string, strlen (string));
123 1672 : }
124 :
125 :
126 : void
127 0 : put_membuf_printf (membuf_t *mb, const char *format, ...)
128 : {
129 : int rc;
130 : va_list arg_ptr;
131 : char *buf;
132 :
133 0 : va_start (arg_ptr, format);
134 0 : rc = gpgrt_vasprintf (&buf, format, arg_ptr);
135 0 : if (rc < 0)
136 0 : mb->out_of_core = errno ? errno : ENOMEM;
137 0 : va_end (arg_ptr);
138 0 : if (rc >= 0)
139 : {
140 0 : put_membuf (mb, buf, strlen (buf));
141 0 : xfree (buf);
142 : }
143 0 : }
144 :
145 :
146 : void *
147 1286 : get_membuf (membuf_t *mb, size_t *len)
148 : {
149 : char *p;
150 :
151 1286 : if (mb->out_of_core)
152 : {
153 0 : if (mb->buf)
154 : {
155 0 : wipememory (mb->buf, mb->len);
156 0 : xfree (mb->buf);
157 0 : mb->buf = NULL;
158 : }
159 0 : gpg_err_set_errno (mb->out_of_core);
160 0 : return NULL;
161 : }
162 :
163 1286 : p = mb->buf;
164 1286 : if (len)
165 789 : *len = mb->len;
166 1286 : mb->buf = NULL;
167 1286 : mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
168 1286 : return p;
169 : }
170 :
171 :
172 : /* Same as get_membuf but shrinks the reallocated space to the
173 : required size. */
174 : void *
175 32 : get_membuf_shrink (membuf_t *mb, size_t *len)
176 : {
177 : void *p, *pp;
178 : size_t dummylen;
179 :
180 32 : if (!len)
181 32 : len = &dummylen;
182 :
183 32 : p = get_membuf (mb, len);
184 32 : if (!p)
185 0 : return NULL;
186 32 : if (*len)
187 : {
188 32 : pp = xtryrealloc (p, *len);
189 32 : if (pp)
190 32 : p = pp;
191 : }
192 :
193 32 : return p;
194 : }
195 :
196 :
197 : /* Peek at the membuf MB. On success a pointer to the buffer is
198 : returned which is valid until the next operation on MB. If LEN is
199 : not NULL the current LEN of the buffer is stored there. On error
200 : NULL is returned and ERRNO is set. */
201 : const void *
202 0 : peek_membuf (membuf_t *mb, size_t *len)
203 : {
204 : const char *p;
205 :
206 0 : if (mb->out_of_core)
207 : {
208 0 : gpg_err_set_errno (mb->out_of_core);
209 0 : return NULL;
210 : }
211 :
212 0 : p = mb->buf;
213 0 : if (len)
214 0 : *len = mb->len;
215 0 : return p;
216 : }
|