• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/blob.c

  1 /*
  2  * blob - library for generating/parsing tagged binary data
  3  *
  4  * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
  5  *
  6  * Permission to use, copy, modify, and/or distribute this software for any
  7  * purpose with or without fee is hereby granted, provided that the above
  8  * copyright notice and this permission notice appear in all copies.
  9  *
 10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17  */
 18 
 19 #include "blob.h"
 20 
 21 static bool
 22 blob_buffer_grow(struct blob_buf *buf, int minlen)
 23 {
 24         struct blob_buf *new;
 25         int delta = ((minlen / 256) + 1) * 256;
 26         new = realloc(buf->buf, buf->buflen + delta);
 27         if (new) {
 28                 buf->buf = new;
 29                 memset(buf->buf + buf->buflen, 0, delta);
 30                 buf->buflen += delta;
 31         }
 32         return !!new;
 33 }
 34 
 35 static void
 36 blob_init(struct blob_attr *attr, int id, unsigned int len)
 37 {
 38         len &= BLOB_ATTR_LEN_MASK;
 39         len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK;
 40         attr->id_len = cpu_to_be32(len);
 41 }
 42 
 43 static inline struct blob_attr *
 44 offset_to_attr(struct blob_buf *buf, int offset)
 45 {
 46         void *ptr = (char *)buf->buf + offset - BLOB_COOKIE;
 47         return ptr;
 48 }
 49 
 50 static inline int
 51 attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
 52 {
 53         return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
 54 }
 55 
 56 bool
 57 blob_buf_grow(struct blob_buf *buf, int required)
 58 {
 59         int offset_head = attr_to_offset(buf, buf->head);
 60 
 61         if ((buf->buflen + required) > BLOB_ATTR_LEN_MASK)
 62                 return false;
 63         if (!buf->grow || !buf->grow(buf, required))
 64                 return false;
 65 
 66         buf->head = offset_to_attr(buf, offset_head);
 67         return true;
 68 }
 69 
 70 static struct blob_attr *
 71 blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)
 72 {
 73         int offset = attr_to_offset(buf, pos);
 74         int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen;
 75         struct blob_attr *attr;
 76 
 77         if (required > 0) {
 78                 if (!blob_buf_grow(buf, required))
 79                         return NULL;
 80                 attr = offset_to_attr(buf, offset);
 81         } else {
 82                 attr = pos;
 83         }
 84 
 85         blob_init(attr, id, payload + sizeof(struct blob_attr));
 86         blob_fill_pad(attr);
 87         return attr;
 88 }
 89 
 90 int
 91 blob_buf_init(struct blob_buf *buf, int id)
 92 {
 93         if (!buf->grow)
 94                 buf->grow = blob_buffer_grow;
 95 
 96         buf->head = buf->buf;
 97         if (blob_add(buf, buf->buf, id, 0) == NULL)
 98                 return -ENOMEM;
 99 
100         return 0;
101 }
102 
103 void
104 blob_buf_free(struct blob_buf *buf)
105 {
106         free(buf->buf);
107         buf->buf = NULL;
108         buf->buflen = 0;
109 }
110 
111 void
112 blob_fill_pad(struct blob_attr *attr)
113 {
114         char *buf = (char *) attr;
115         int len = blob_pad_len(attr);
116         int delta = len - blob_raw_len(attr);
117 
118         if (delta > 0)
119                 memset(buf + len - delta, 0, delta);
120 }
121 
122 void
123 blob_set_raw_len(struct blob_attr *attr, unsigned int len)
124 {
125         len &= BLOB_ATTR_LEN_MASK;
126         attr->id_len &= ~cpu_to_be32(BLOB_ATTR_LEN_MASK);
127         attr->id_len |= cpu_to_be32(len);
128 }
129 
130 struct blob_attr *
131 blob_new(struct blob_buf *buf, int id, int payload)
132 {
133         struct blob_attr *attr;
134 
135         attr = blob_add(buf, blob_next(buf->head), id, payload);
136         if (!attr)
137                 return NULL;
138 
139         blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr));
140         return attr;
141 }
142 
143 struct blob_attr *
144 blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)
145 {
146         struct blob_attr *attr;
147 
148         if (len < sizeof(struct blob_attr) || !ptr)
149                 return NULL;
150 
151         attr = blob_add(buf, blob_next(buf->head), 0, len - sizeof(struct blob_attr));
152         if (!attr)
153                 return NULL;
154         blob_set_raw_len(buf->head, blob_pad_len(buf->head) + len);
155         memcpy(attr, ptr, len);
156         return attr;
157 }
158 
159 struct blob_attr *
160 blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)
161 {
162         struct blob_attr *attr;
163 
164         attr = blob_new(buf, id, len);
165         if (!attr)
166                 return NULL;
167 
168         if (ptr)
169                 memcpy(blob_data(attr), ptr, len);
170         return attr;
171 }
172 
173 void *
174 blob_nest_start(struct blob_buf *buf, int id)
175 {
176         unsigned long offset = attr_to_offset(buf, buf->head);
177         buf->head = blob_new(buf, id, 0);
178         if (!buf->head)
179                 return NULL;
180         return (void *) offset;
181 }
182 
183 void
184 blob_nest_end(struct blob_buf *buf, void *cookie)
185 {
186         struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie);
187         blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head));
188         buf->head = attr;
189 }
190 
191 static const size_t blob_type_minlen[BLOB_ATTR_LAST] = {
192         [BLOB_ATTR_STRING] = 1,
193         [BLOB_ATTR_INT8] = sizeof(uint8_t),
194         [BLOB_ATTR_INT16] = sizeof(uint16_t),
195         [BLOB_ATTR_INT32] = sizeof(uint32_t),
196         [BLOB_ATTR_INT64] = sizeof(uint64_t),
197         [BLOB_ATTR_DOUBLE] = sizeof(double),
198 };
199 
200 bool
201 blob_check_type(const void *ptr, unsigned int len, int type)
202 {
203         const char *data = ptr;
204 
205         if (type >= BLOB_ATTR_LAST)
206                 return false;
207 
208         if (type >= BLOB_ATTR_INT8 && type <= BLOB_ATTR_INT64) {
209                 if (len != blob_type_minlen[type])
210                         return false;
211         } else {
212                 if (len < blob_type_minlen[type])
213                         return false;
214         }
215 
216         if (type == BLOB_ATTR_STRING && data[len - 1] != 0)
217                 return false;
218 
219         return true;
220 }
221 
222 static int
223 blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
224 {
225         int id;
226         size_t len;
227         int found = 0;
228         size_t data_len;
229 
230         if (!attr || attr_len < sizeof(struct blob_attr))
231                 return 0;
232 
233         id = blob_id(attr);
234         if (id >= max)
235                 return 0;
236 
237         len = blob_raw_len(attr);
238         if (len > attr_len || len < sizeof(struct blob_attr))
239                 return 0;
240 
241         data_len = blob_len(attr);
242         if (data_len > len)
243                 return 0;
244 
245         if (info) {
246                 int type = info[id].type;
247 
248                 if (type < BLOB_ATTR_LAST) {
249                         if (!blob_check_type(blob_data(attr), data_len, type))
250                                 return 0;
251                 }
252 
253                 if (info[id].minlen && len < info[id].minlen)
254                         return 0;
255 
256                 if (info[id].maxlen && len > info[id].maxlen)
257                         return 0;
258 
259                 if (info[id].validate && !info[id].validate(&info[id], attr))
260                         return 0;
261         }
262 
263         if (!data[id])
264                 found++;
265 
266         data[id] = attr;
267         return found;
268 }
269 
270 int
271 blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
272 {
273         struct blob_attr *pos;
274         size_t len = 0;
275         int found = 0;
276         size_t rem;
277 
278         if (!attr || attr_len < sizeof(struct blob_attr))
279                 return 0;
280 
281         len = blob_raw_len(attr);
282         if (attr_len < len)
283                 return 0;
284 
285         memset(data, 0, sizeof(struct blob_attr *) * max);
286         blob_for_each_attr_len(pos, attr, len, rem) {
287                 found += blob_parse_attr(pos, rem, data, info, max);
288         }
289 
290         return found;
291 }
292 
293 /* use only on trusted input, otherwise consider blob_parse_untrusted */
294 int
295 blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
296 {
297         struct blob_attr *pos;
298         int found = 0;
299         size_t rem;
300 
301         memset(data, 0, sizeof(struct blob_attr *) * max);
302         blob_for_each_attr(pos, attr, rem) {
303                 found += blob_parse_attr(pos, rem, data, info, max);
304         }
305 
306         return found;
307 }
308 
309 bool
310 blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
311 {
312         if (!a1 && !a2)
313                 return true;
314 
315         if (!a1 || !a2)
316                 return false;
317 
318         if (blob_pad_len(a1) != blob_pad_len(a2))
319                 return false;
320 
321         return !memcmp(a1, a2, blob_pad_len(a1));
322 }
323 
324 struct blob_attr *
325 blob_memdup(struct blob_attr *attr)
326 {
327         struct blob_attr *ret;
328         int size = blob_pad_len(attr);
329 
330         ret = malloc(size);
331         if (!ret)
332                 return NULL;
333 
334         memcpy(ret, attr, size);
335         return ret;
336 }
337 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt