/src/p11-kit/common/buffer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2007, 2012 Stefan Walter |
3 | | * Copyright (C) 2013 Red Hat Inc. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * |
9 | | * * Redistributions of source code must retain the above |
10 | | * copyright notice, this list of conditions and the |
11 | | * following disclaimer. |
12 | | * * Redistributions in binary form must reproduce the |
13 | | * above copyright notice, this list of conditions and |
14 | | * the following disclaimer in the documentation and/or |
15 | | * other materials provided with the distribution. |
16 | | * * The names of contributors to this software may not be |
17 | | * used to endorse or promote products derived from this |
18 | | * software without specific prior written permission. |
19 | | * |
20 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
23 | | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
24 | | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
25 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
26 | | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
27 | | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
28 | | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
29 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
30 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
31 | | * DAMAGE. |
32 | | * |
33 | | * Author: Stef Walter <stef@thewalter.net> |
34 | | */ |
35 | | |
36 | | #include "config.h" |
37 | | |
38 | | #include "buffer.h" |
39 | | #include "debug.h" |
40 | | |
41 | | #include <assert.h> |
42 | | #include <stdint.h> |
43 | | #include <stdlib.h> |
44 | | #include <string.h> |
45 | | #include <stdarg.h> |
46 | | |
47 | | static bool |
48 | | buffer_realloc (p11_buffer *buffer, |
49 | | size_t size) |
50 | 76 | { |
51 | 76 | void *data; |
52 | | |
53 | | /* Memory owned elsewhere can't be reallocated */ |
54 | 76 | return_val_if_fail (buffer->frealloc != NULL, false); |
55 | | |
56 | | /* Reallocate built in buffer using allocator */ |
57 | 76 | data = (buffer->frealloc) (buffer->data, size); |
58 | 76 | if (!data && size > 0) { |
59 | 0 | p11_buffer_fail (buffer); |
60 | 0 | return_val_if_reached (false); |
61 | 0 | } |
62 | | |
63 | 76 | buffer->data = data; |
64 | 76 | buffer->size = size; |
65 | 76 | return true; |
66 | 76 | } |
67 | | |
68 | | bool |
69 | | p11_buffer_init (p11_buffer *buffer, |
70 | | size_t reserve) |
71 | 38 | { |
72 | 38 | p11_buffer_init_full (buffer, NULL, 0, 0, realloc, free); |
73 | 38 | return buffer_realloc (buffer, reserve); |
74 | 38 | } |
75 | | |
76 | | bool |
77 | | p11_buffer_init_null (p11_buffer *buffer, |
78 | | size_t reserve) |
79 | 0 | { |
80 | 0 | p11_buffer_init_full (buffer, NULL, 0, P11_BUFFER_NULL, realloc, free); |
81 | 0 | return buffer_realloc (buffer, reserve); |
82 | 0 | } |
83 | | |
84 | | void |
85 | | p11_buffer_init_full (p11_buffer *buffer, |
86 | | void *data, |
87 | | size_t len, |
88 | | int flags, |
89 | | void * (* frealloc) (void *, size_t), |
90 | | void (* ffree) (void *)) |
91 | 38 | { |
92 | 38 | memset (buffer, 0, sizeof (*buffer)); |
93 | | |
94 | 38 | buffer->data = data; |
95 | 38 | buffer->len = len; |
96 | 38 | buffer->size = len; |
97 | 38 | buffer->flags = flags; |
98 | 38 | buffer->frealloc = frealloc; |
99 | 38 | buffer->ffree = ffree; |
100 | | |
101 | 38 | return_if_fail (!(flags & P11_BUFFER_FAILED)); |
102 | 38 | } |
103 | | |
104 | | void |
105 | | p11_buffer_uninit (p11_buffer *buffer) |
106 | 38 | { |
107 | 38 | return_if_fail (buffer != NULL); |
108 | | |
109 | 38 | if (buffer->ffree && buffer->data) |
110 | 38 | (buffer->ffree) (buffer->data); |
111 | 38 | memset (buffer, 0, sizeof (*buffer)); |
112 | 38 | } |
113 | | |
114 | | void * |
115 | | p11_buffer_steal (p11_buffer *buffer, |
116 | | size_t *length) |
117 | 0 | { |
118 | 0 | void *data; |
119 | |
|
120 | 0 | return_val_if_fail (p11_buffer_ok (buffer), NULL); |
121 | | |
122 | 0 | if (length) |
123 | 0 | *length = buffer->len; |
124 | 0 | data = buffer->data; |
125 | |
|
126 | 0 | buffer->data = NULL; |
127 | 0 | buffer->size = 0; |
128 | 0 | buffer->len = 0; |
129 | 0 | return data; |
130 | 0 | } |
131 | | |
132 | | bool |
133 | | p11_buffer_reset (p11_buffer *buffer, |
134 | | size_t reserve) |
135 | 43 | { |
136 | 43 | buffer->flags &= ~P11_BUFFER_FAILED; |
137 | 43 | buffer->len = 0; |
138 | | |
139 | 43 | if (reserve < buffer->size) |
140 | 43 | return true; |
141 | 0 | return buffer_realloc (buffer, reserve); |
142 | 43 | } |
143 | | |
144 | | void * |
145 | | p11_buffer_append (p11_buffer *buffer, |
146 | | size_t length) |
147 | 223 | { |
148 | 223 | unsigned char *data; |
149 | 223 | size_t terminator; |
150 | 223 | size_t newlen; |
151 | 223 | size_t reserve; |
152 | 223 | size_t offset; |
153 | | |
154 | 223 | return_val_if_fail (p11_buffer_ok (buffer), NULL); |
155 | | |
156 | 223 | terminator = (buffer->flags & P11_BUFFER_NULL) ? 1 : 0; |
157 | | |
158 | | /* Check for unlikely and unrecoverable integer overflow */ |
159 | 223 | return_val_if_fail (SIZE_MAX - (terminator + length) > buffer->len, NULL); |
160 | | |
161 | 223 | reserve = terminator + length + buffer->len; |
162 | | |
163 | 223 | if (reserve > buffer->size) { |
164 | | |
165 | | /* Calculate a new length, minimize number of buffer allocations */ |
166 | 38 | return_val_if_fail (buffer->size < SIZE_MAX / 2, NULL); |
167 | 38 | newlen = buffer->size * 2; |
168 | 38 | if (!newlen) |
169 | 38 | newlen = 16; |
170 | 38 | if (reserve > newlen) |
171 | 38 | newlen = reserve; |
172 | | |
173 | 38 | if (!buffer_realloc (buffer, newlen)) |
174 | 0 | return_val_if_reached (NULL); |
175 | 38 | } |
176 | | |
177 | 223 | data = buffer->data; |
178 | 223 | offset = buffer->len; |
179 | 223 | buffer->len += length; |
180 | 223 | if (terminator) |
181 | 0 | data[buffer->len] = '\0'; |
182 | 223 | return data + offset; |
183 | 223 | } |
184 | | |
185 | | void |
186 | | p11_buffer_add (p11_buffer *buffer, |
187 | | const void *data, |
188 | | ssize_t length) |
189 | 81 | { |
190 | 81 | void *at; |
191 | | |
192 | 81 | if (length < 0) |
193 | 0 | length = strlen (data); |
194 | | |
195 | 81 | at = p11_buffer_append (buffer, length); |
196 | 81 | return_if_fail (at != NULL); |
197 | 81 | memcpy (at, data, length); |
198 | 81 | } |