diff options
Diffstat (limited to 'src/service/fs/meta_data.c')
-rw-r--r-- | src/service/fs/meta_data.c | 1238 |
1 files changed, 1238 insertions, 0 deletions
diff --git a/src/service/fs/meta_data.c b/src/service/fs/meta_data.c new file mode 100644 index 000000000..b3db0e6c7 --- /dev/null +++ b/src/service/fs/meta_data.c | |||
@@ -0,0 +1,1238 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/meta_data.c | ||
23 | * @brief Storing of meta data | ||
24 | * @author Christian Grothoff | ||
25 | * @author Martin Schanzenbach | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_fs_service.h" | ||
30 | |||
31 | /** | ||
32 | * Maximum size allowed for meta data written/read from disk. | ||
33 | * File-sharing limits to 64k, so this should be rather generous. | ||
34 | */ | ||
35 | #define MAX_META_DATA (1024 * 1024) | ||
36 | |||
37 | |||
38 | #define LOG(kind, ...) GNUNET_log_from (kind, "fs-meta-data", \ | ||
39 | __VA_ARGS__) | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Meta data item. | ||
44 | */ | ||
45 | struct MetaItem | ||
46 | { | ||
47 | /** | ||
48 | * This is a doubly linked list. | ||
49 | */ | ||
50 | struct MetaItem *next; | ||
51 | |||
52 | /** | ||
53 | * This is a doubly linked list. | ||
54 | */ | ||
55 | struct MetaItem *prev; | ||
56 | |||
57 | /** | ||
58 | * Name of the extracting plugin. | ||
59 | */ | ||
60 | char *plugin_name; | ||
61 | |||
62 | /** | ||
63 | * Mime-type of data. | ||
64 | */ | ||
65 | char *mime_type; | ||
66 | |||
67 | /** | ||
68 | * The actual meta data. | ||
69 | */ | ||
70 | char *data; | ||
71 | |||
72 | /** | ||
73 | * Number of bytes in 'data'. | ||
74 | */ | ||
75 | size_t data_size; | ||
76 | |||
77 | /** | ||
78 | * Type of the meta data. | ||
79 | */ | ||
80 | enum EXTRACTOR_MetaType type; | ||
81 | |||
82 | /** | ||
83 | * Format of the meta data. | ||
84 | */ | ||
85 | enum EXTRACTOR_MetaFormat format; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * Meta data to associate with a file, directory or namespace. | ||
90 | */ | ||
91 | struct GNUNET_FS_MetaData | ||
92 | { | ||
93 | /** | ||
94 | * Head of linked list of the meta data items. | ||
95 | */ | ||
96 | struct MetaItem *items_head; | ||
97 | |||
98 | /** | ||
99 | * Tail of linked list of the meta data items. | ||
100 | */ | ||
101 | struct MetaItem *items_tail; | ||
102 | |||
103 | /** | ||
104 | * Complete serialized and compressed buffer of the items. | ||
105 | * NULL if we have not computed that buffer yet. | ||
106 | */ | ||
107 | char *sbuf; | ||
108 | |||
109 | /** | ||
110 | * Number of bytes in 'sbuf'. 0 if the buffer is stale. | ||
111 | */ | ||
112 | size_t sbuf_size; | ||
113 | |||
114 | /** | ||
115 | * Number of items in the linked list. | ||
116 | */ | ||
117 | unsigned int item_count; | ||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Create a fresh struct FS_MetaData token. | ||
123 | * | ||
124 | * @return empty meta-data container | ||
125 | */ | ||
126 | struct GNUNET_FS_MetaData * | ||
127 | GNUNET_FS_meta_data_create () | ||
128 | { | ||
129 | return GNUNET_new (struct GNUNET_FS_MetaData); | ||
130 | } | ||
131 | |||
132 | |||
133 | /** | ||
134 | * Free meta data item. | ||
135 | * | ||
136 | * @param mi item to free | ||
137 | */ | ||
138 | static void | ||
139 | meta_item_free (struct MetaItem *mi) | ||
140 | { | ||
141 | GNUNET_free (mi->plugin_name); | ||
142 | GNUNET_free (mi->mime_type); | ||
143 | GNUNET_free (mi->data); | ||
144 | GNUNET_free (mi); | ||
145 | } | ||
146 | |||
147 | |||
148 | /** | ||
149 | * The meta data has changed, invalidate its serialization | ||
150 | * buffer. | ||
151 | * | ||
152 | * @param md meta data that changed | ||
153 | */ | ||
154 | static void | ||
155 | invalidate_sbuf (struct GNUNET_FS_MetaData *md) | ||
156 | { | ||
157 | if (NULL == md->sbuf) | ||
158 | return; | ||
159 | GNUNET_free (md->sbuf); | ||
160 | md->sbuf = NULL; | ||
161 | md->sbuf_size = 0; | ||
162 | } | ||
163 | |||
164 | |||
165 | void | ||
166 | GNUNET_FS_meta_data_destroy (struct GNUNET_FS_MetaData *md) | ||
167 | { | ||
168 | struct MetaItem *pos; | ||
169 | |||
170 | if (NULL == md) | ||
171 | return; | ||
172 | while (NULL != (pos = md->items_head)) | ||
173 | { | ||
174 | GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos); | ||
175 | meta_item_free (pos); | ||
176 | } | ||
177 | GNUNET_free (md->sbuf); | ||
178 | GNUNET_free (md); | ||
179 | } | ||
180 | |||
181 | |||
182 | void | ||
183 | GNUNET_FS_meta_data_clear (struct GNUNET_FS_MetaData *md) | ||
184 | { | ||
185 | struct MetaItem *mi; | ||
186 | |||
187 | if (NULL == md) | ||
188 | return; | ||
189 | while (NULL != (mi = md->items_head)) | ||
190 | { | ||
191 | GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, mi); | ||
192 | meta_item_free (mi); | ||
193 | } | ||
194 | GNUNET_free (md->sbuf); | ||
195 | memset (md, 0, sizeof(struct GNUNET_FS_MetaData)); | ||
196 | } | ||
197 | |||
198 | |||
199 | int | ||
200 | GNUNET_FS_meta_data_test_equal (const struct GNUNET_FS_MetaData | ||
201 | *md1, | ||
202 | const struct GNUNET_FS_MetaData | ||
203 | *md2) | ||
204 | { | ||
205 | struct MetaItem *i; | ||
206 | struct MetaItem *j; | ||
207 | int found; | ||
208 | |||
209 | if (md1 == md2) | ||
210 | return GNUNET_YES; | ||
211 | if (md1->item_count != md2->item_count) | ||
212 | return GNUNET_NO; | ||
213 | for (i = md1->items_head; NULL != i; i = i->next) | ||
214 | { | ||
215 | found = GNUNET_NO; | ||
216 | for (j = md2->items_head; NULL != j; j = j->next) | ||
217 | { | ||
218 | if ((i->type == j->type) && (i->format == j->format) && | ||
219 | (i->data_size == j->data_size) && | ||
220 | (0 == memcmp (i->data, j->data, i->data_size))) | ||
221 | { | ||
222 | found = GNUNET_YES; | ||
223 | break; | ||
224 | } | ||
225 | if (j->data_size < i->data_size) | ||
226 | break; /* elements are sorted by (decreasing) size... */ | ||
227 | } | ||
228 | if (GNUNET_NO == found) | ||
229 | return GNUNET_NO; | ||
230 | } | ||
231 | return GNUNET_YES; | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Extend metadata. Note that the list of meta data items is | ||
237 | * sorted by size (largest first). | ||
238 | * | ||
239 | * @param md metadata to extend | ||
240 | * @param plugin_name name of the plugin that produced this value; | ||
241 | * special values can be used (e.g. '<zlib>' for zlib being | ||
242 | * used in the main libextractor library and yielding | ||
243 | * meta data). | ||
244 | * @param type libextractor-type describing the meta data | ||
245 | * @param format basic format information about data | ||
246 | * @param data_mime_type mime-type of data (not of the original file); | ||
247 | * can be NULL (if mime-type is not known) | ||
248 | * @param data actual meta-data found | ||
249 | * @param data_size number of bytes in @a data | ||
250 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if this entry already exists | ||
251 | * data_mime_type and plugin_name are not considered for "exists" checks | ||
252 | */ | ||
253 | int | ||
254 | GNUNET_FS_meta_data_insert (struct GNUNET_FS_MetaData *md, | ||
255 | const char *plugin_name, | ||
256 | enum EXTRACTOR_MetaType type, | ||
257 | enum EXTRACTOR_MetaFormat format, | ||
258 | const char *data_mime_type, const char *data, | ||
259 | size_t data_size) | ||
260 | { | ||
261 | struct MetaItem *pos; | ||
262 | struct MetaItem *mi; | ||
263 | char *p; | ||
264 | |||
265 | if ((EXTRACTOR_METAFORMAT_UTF8 == format) || | ||
266 | (EXTRACTOR_METAFORMAT_C_STRING == format)) | ||
267 | GNUNET_break ('\0' == data[data_size - 1]); | ||
268 | |||
269 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
270 | { | ||
271 | if (pos->data_size < data_size) | ||
272 | break; /* elements are sorted by size in the list */ | ||
273 | if ((pos->type == type) && (pos->data_size == data_size) && | ||
274 | (0 == memcmp (pos->data, data, data_size))) | ||
275 | { | ||
276 | if ((NULL == pos->mime_type) && (NULL != data_mime_type)) | ||
277 | { | ||
278 | pos->mime_type = GNUNET_strdup (data_mime_type); | ||
279 | invalidate_sbuf (md); | ||
280 | } | ||
281 | if ((EXTRACTOR_METAFORMAT_C_STRING == pos->format) && | ||
282 | (EXTRACTOR_METAFORMAT_UTF8 == format)) | ||
283 | { | ||
284 | pos->format = EXTRACTOR_METAFORMAT_UTF8; | ||
285 | invalidate_sbuf (md); | ||
286 | } | ||
287 | return GNUNET_SYSERR; | ||
288 | } | ||
289 | } | ||
290 | md->item_count++; | ||
291 | mi = GNUNET_new (struct MetaItem); | ||
292 | mi->type = type; | ||
293 | mi->format = format; | ||
294 | mi->data_size = data_size; | ||
295 | if (NULL == pos) | ||
296 | GNUNET_CONTAINER_DLL_insert_tail (md->items_head, | ||
297 | md->items_tail, | ||
298 | mi); | ||
299 | else | ||
300 | GNUNET_CONTAINER_DLL_insert_after (md->items_head, | ||
301 | md->items_tail, | ||
302 | pos->prev, | ||
303 | mi); | ||
304 | mi->mime_type = | ||
305 | (NULL == data_mime_type) ? NULL : GNUNET_strdup (data_mime_type); | ||
306 | mi->plugin_name = (NULL == plugin_name) ? NULL : GNUNET_strdup (plugin_name); | ||
307 | mi->data = GNUNET_malloc (data_size); | ||
308 | GNUNET_memcpy (mi->data, data, data_size); | ||
309 | /* change all dir separators to POSIX style ('/') */ | ||
310 | if ((EXTRACTOR_METATYPE_FILENAME == type) || | ||
311 | (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type)) | ||
312 | { | ||
313 | p = mi->data; | ||
314 | while (('\0' != *p) && (p < mi->data + data_size)) | ||
315 | { | ||
316 | if ('\\' == *p) | ||
317 | *p = '/'; | ||
318 | p++; | ||
319 | } | ||
320 | } | ||
321 | invalidate_sbuf (md); | ||
322 | return GNUNET_OK; | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * Merge given meta data. | ||
328 | * | ||
329 | * @param cls the `struct GNUNET_FS_MetaData` to merge into | ||
330 | * @param plugin_name name of the plugin that produced this value; | ||
331 | * special values can be used (e.g. '<zlib>' for zlib being | ||
332 | * used in the main libextractor library and yielding | ||
333 | * meta data). | ||
334 | * @param type libextractor-type describing the meta data | ||
335 | * @param format basic format information about data | ||
336 | * @param data_mime_type mime-type of data (not of the original file); | ||
337 | * can be NULL (if mime-type is not known) | ||
338 | * @param data actual meta-data found | ||
339 | * @param data_size number of bytes in @a data | ||
340 | * @return 0 (to continue) | ||
341 | */ | ||
342 | static int | ||
343 | merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, | ||
344 | enum EXTRACTOR_MetaFormat format, const char *data_mime_type, | ||
345 | const char *data, size_t data_size) | ||
346 | { | ||
347 | struct GNUNET_FS_MetaData *md = cls; | ||
348 | |||
349 | (void) GNUNET_FS_meta_data_insert (md, plugin_name, type, format, | ||
350 | data_mime_type, data, data_size); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | |||
355 | void | ||
356 | GNUNET_FS_meta_data_merge (struct GNUNET_FS_MetaData *md, | ||
357 | const struct GNUNET_FS_MetaData *in) | ||
358 | { | ||
359 | GNUNET_FS_meta_data_iterate (in, &merge_helper, md); | ||
360 | } | ||
361 | |||
362 | |||
363 | int | ||
364 | GNUNET_FS_meta_data_delete (struct GNUNET_FS_MetaData *md, | ||
365 | enum EXTRACTOR_MetaType type, | ||
366 | const char *data, size_t data_size) | ||
367 | { | ||
368 | struct MetaItem *pos; | ||
369 | |||
370 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
371 | { | ||
372 | if (pos->data_size < data_size) | ||
373 | break; /* items are sorted by (decreasing) size */ | ||
374 | if ((pos->type == type) && | ||
375 | ((NULL == data) || | ||
376 | ((pos->data_size == data_size) && | ||
377 | (0 == memcmp (pos->data, data, data_size))))) | ||
378 | { | ||
379 | GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos); | ||
380 | meta_item_free (pos); | ||
381 | md->item_count--; | ||
382 | invalidate_sbuf (md); | ||
383 | return GNUNET_OK; | ||
384 | } | ||
385 | } | ||
386 | return GNUNET_SYSERR; | ||
387 | } | ||
388 | |||
389 | |||
390 | void | ||
391 | GNUNET_FS_meta_data_add_publication_date (struct | ||
392 | GNUNET_FS_MetaData *md) | ||
393 | { | ||
394 | const char *dat; | ||
395 | struct GNUNET_TIME_Absolute t; | ||
396 | |||
397 | t = GNUNET_TIME_absolute_get (); | ||
398 | GNUNET_FS_meta_data_delete (md, | ||
399 | EXTRACTOR_METATYPE_PUBLICATION_DATE, | ||
400 | NULL, 0); | ||
401 | dat = GNUNET_STRINGS_absolute_time_to_string (t); | ||
402 | GNUNET_FS_meta_data_insert (md, "<gnunet>", | ||
403 | EXTRACTOR_METATYPE_PUBLICATION_DATE, | ||
404 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
405 | dat, strlen (dat) + 1); | ||
406 | } | ||
407 | |||
408 | |||
409 | /** | ||
410 | * Iterate over MD entries. | ||
411 | * | ||
412 | * @param md metadata to inspect | ||
413 | * @param iter function to call on each entry | ||
414 | * @param iter_cls closure for iterator | ||
415 | * @return number of entries | ||
416 | */ | ||
417 | int | ||
418 | GNUNET_FS_meta_data_iterate (const struct GNUNET_FS_MetaData *md, | ||
419 | EXTRACTOR_MetaDataProcessor iter, | ||
420 | void *iter_cls) | ||
421 | { | ||
422 | struct MetaItem *pos; | ||
423 | |||
424 | if (NULL == md) | ||
425 | return 0; | ||
426 | if (NULL == iter) | ||
427 | return md->item_count; | ||
428 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
429 | if (0 != | ||
430 | iter (iter_cls, pos->plugin_name, pos->type, pos->format, | ||
431 | pos->mime_type, pos->data, pos->data_size)) | ||
432 | return md->item_count; | ||
433 | return md->item_count; | ||
434 | } | ||
435 | |||
436 | |||
437 | char * | ||
438 | GNUNET_FS_meta_data_get_by_type (const struct | ||
439 | GNUNET_FS_MetaData *md, | ||
440 | enum EXTRACTOR_MetaType type) | ||
441 | { | ||
442 | struct MetaItem *pos; | ||
443 | |||
444 | if (NULL == md) | ||
445 | return NULL; | ||
446 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
447 | if ((type == pos->type) && | ||
448 | ((pos->format == EXTRACTOR_METAFORMAT_UTF8) || | ||
449 | (pos->format == EXTRACTOR_METAFORMAT_C_STRING))) | ||
450 | return GNUNET_strdup (pos->data); | ||
451 | return NULL; | ||
452 | } | ||
453 | |||
454 | |||
455 | char * | ||
456 | GNUNET_FS_meta_data_get_first_by_types (const struct | ||
457 | GNUNET_FS_MetaData *md, | ||
458 | ...) | ||
459 | { | ||
460 | char *ret; | ||
461 | va_list args; | ||
462 | int type; | ||
463 | |||
464 | if (NULL == md) | ||
465 | return NULL; | ||
466 | ret = NULL; | ||
467 | va_start (args, md); | ||
468 | while (1) | ||
469 | { | ||
470 | type = va_arg (args, int); | ||
471 | if (-1 == type) | ||
472 | break; | ||
473 | if (NULL != (ret = GNUNET_FS_meta_data_get_by_type (md, type))) | ||
474 | break; | ||
475 | } | ||
476 | va_end (args); | ||
477 | return ret; | ||
478 | } | ||
479 | |||
480 | |||
481 | /** | ||
482 | * Get a thumbnail from the meta-data (if present). | ||
483 | * | ||
484 | * @param md metadata to get the thumbnail from | ||
485 | * @param thumb will be set to the thumbnail data. Must be | ||
486 | * freed by the caller! | ||
487 | * @return number of bytes in thumbnail, 0 if not available | ||
488 | */ | ||
489 | size_t | ||
490 | GNUNET_FS_meta_data_get_thumbnail (const struct GNUNET_FS_MetaData | ||
491 | *md, unsigned char **thumb) | ||
492 | { | ||
493 | struct MetaItem *pos; | ||
494 | struct MetaItem *match; | ||
495 | |||
496 | if (NULL == md) | ||
497 | return 0; | ||
498 | match = NULL; | ||
499 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
500 | { | ||
501 | if ((NULL != pos->mime_type) && | ||
502 | (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) && | ||
503 | (EXTRACTOR_METAFORMAT_BINARY == pos->format)) | ||
504 | { | ||
505 | if (NULL == match) | ||
506 | match = pos; | ||
507 | else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) && | ||
508 | (pos->type == EXTRACTOR_METATYPE_THUMBNAIL)) | ||
509 | match = pos; | ||
510 | } | ||
511 | } | ||
512 | if ((NULL == match) || (0 == match->data_size)) | ||
513 | return 0; | ||
514 | *thumb = GNUNET_malloc (match->data_size); | ||
515 | GNUNET_memcpy (*thumb, match->data, match->data_size); | ||
516 | return match->data_size; | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Duplicate a `struct GNUNET_FS_MetaData`. | ||
522 | * | ||
523 | * @param md what to duplicate | ||
524 | * @return duplicate meta-data container | ||
525 | */ | ||
526 | struct GNUNET_FS_MetaData * | ||
527 | GNUNET_FS_meta_data_duplicate (const struct GNUNET_FS_MetaData | ||
528 | *md) | ||
529 | { | ||
530 | struct GNUNET_FS_MetaData *ret; | ||
531 | struct MetaItem *pos; | ||
532 | |||
533 | if (NULL == md) | ||
534 | return NULL; | ||
535 | ret = GNUNET_FS_meta_data_create (); | ||
536 | for (pos = md->items_tail; NULL != pos; pos = pos->prev) | ||
537 | GNUNET_FS_meta_data_insert (ret, pos->plugin_name, pos->type, | ||
538 | pos->format, pos->mime_type, pos->data, | ||
539 | pos->data_size); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | |||
544 | /** | ||
545 | * Flag in 'version' that indicates compressed meta-data. | ||
546 | */ | ||
547 | #define HEADER_COMPRESSED 0x80000000 | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Bits in 'version' that give the version number. | ||
552 | */ | ||
553 | #define HEADER_VERSION_MASK 0x7FFFFFFF | ||
554 | |||
555 | |||
556 | /** | ||
557 | * Header for serialized meta data. | ||
558 | */ | ||
559 | struct MetaDataHeader | ||
560 | { | ||
561 | /** | ||
562 | * The version of the MD serialization. The highest bit is used to | ||
563 | * indicate compression. | ||
564 | * | ||
565 | * Version 0 is traditional (pre-0.9) meta data (unsupported) | ||
566 | * Version is 1 for a NULL pointer | ||
567 | * Version 2 is for 0.9.x (and possibly higher) | ||
568 | * Other version numbers are not yet defined. | ||
569 | */ | ||
570 | uint32_t version; | ||
571 | |||
572 | /** | ||
573 | * How many MD entries are there? | ||
574 | */ | ||
575 | uint32_t entries; | ||
576 | |||
577 | /** | ||
578 | * Size of the decompressed meta data. | ||
579 | */ | ||
580 | uint32_t size; | ||
581 | |||
582 | /** | ||
583 | * This is followed by 'entries' values of type 'struct MetaDataEntry' | ||
584 | * and then by 'entry' plugin names, mime-types and data blocks | ||
585 | * as specified in those meta data entries. | ||
586 | */ | ||
587 | }; | ||
588 | |||
589 | |||
590 | /** | ||
591 | * Entry of serialized meta data. | ||
592 | */ | ||
593 | struct MetaDataEntry | ||
594 | { | ||
595 | /** | ||
596 | * Meta data type. Corresponds to an 'enum EXTRACTOR_MetaType' | ||
597 | */ | ||
598 | uint32_t type; | ||
599 | |||
600 | /** | ||
601 | * Meta data format. Corresponds to an 'enum EXTRACTOR_MetaFormat' | ||
602 | */ | ||
603 | uint32_t format; | ||
604 | |||
605 | /** | ||
606 | * Number of bytes of meta data. | ||
607 | */ | ||
608 | uint32_t data_size; | ||
609 | |||
610 | /** | ||
611 | * Number of bytes in the plugin name including 0-terminator. 0 for NULL. | ||
612 | */ | ||
613 | uint32_t plugin_name_len; | ||
614 | |||
615 | /** | ||
616 | * Number of bytes in the mime type including 0-terminator. 0 for NULL. | ||
617 | */ | ||
618 | uint32_t mime_type_len; | ||
619 | }; | ||
620 | |||
621 | |||
622 | /** | ||
623 | * Serialize meta-data to target. | ||
624 | * | ||
625 | * @param md metadata to serialize | ||
626 | * @param target where to write the serialized metadata; | ||
627 | * *target can be NULL, in which case memory is allocated | ||
628 | * @param max maximum number of bytes available in target | ||
629 | * @param opt is it ok to just write SOME of the | ||
630 | * meta-data to match the size constraint, | ||
631 | * possibly discarding some data? | ||
632 | * @return number of bytes written on success, | ||
633 | * #GNUNET_SYSERR on error (typically: not enough | ||
634 | * space) | ||
635 | */ | ||
636 | ssize_t | ||
637 | GNUNET_FS_meta_data_serialize (const struct GNUNET_FS_MetaData | ||
638 | *md, char **target, size_t max, | ||
639 | enum | ||
640 | GNUNET_FS_MetaDataSerializationOptions | ||
641 | opt) | ||
642 | { | ||
643 | struct GNUNET_FS_MetaData *vmd; | ||
644 | struct MetaItem *pos; | ||
645 | struct MetaDataHeader ihdr; | ||
646 | struct MetaDataHeader *hdr; | ||
647 | struct MetaDataEntry *ent; | ||
648 | char *dst; | ||
649 | unsigned int i; | ||
650 | uint64_t msize; | ||
651 | size_t off; | ||
652 | char *mdata; | ||
653 | char *cdata; | ||
654 | size_t mlen; | ||
655 | size_t plen; | ||
656 | size_t size; | ||
657 | size_t left; | ||
658 | size_t clen; | ||
659 | size_t rlen; | ||
660 | int comp; | ||
661 | |||
662 | if (max < sizeof(struct MetaDataHeader)) | ||
663 | return GNUNET_SYSERR; /* far too small */ | ||
664 | if (NULL == md) | ||
665 | return 0; | ||
666 | |||
667 | if (NULL != md->sbuf) | ||
668 | { | ||
669 | /* try to use serialization cache */ | ||
670 | if (md->sbuf_size <= max) | ||
671 | { | ||
672 | if (NULL == *target) | ||
673 | *target = GNUNET_malloc (md->sbuf_size); | ||
674 | GNUNET_memcpy (*target, md->sbuf, md->sbuf_size); | ||
675 | return md->sbuf_size; | ||
676 | } | ||
677 | if (0 == (opt & GNUNET_FS_META_DATA_SERIALIZE_PART)) | ||
678 | return GNUNET_SYSERR; /* can say that this will fail */ | ||
679 | /* need to compute a partial serialization, sbuf useless ... */ | ||
680 | } | ||
681 | dst = NULL; | ||
682 | msize = 0; | ||
683 | for (pos = md->items_tail; NULL != pos; pos = pos->prev) | ||
684 | { | ||
685 | msize += sizeof(struct MetaDataEntry); | ||
686 | msize += pos->data_size; | ||
687 | if (NULL != pos->plugin_name) | ||
688 | msize += strlen (pos->plugin_name) + 1; | ||
689 | if (NULL != pos->mime_type) | ||
690 | msize += strlen (pos->mime_type) + 1; | ||
691 | } | ||
692 | size = (size_t) msize; | ||
693 | if (size != msize) | ||
694 | { | ||
695 | GNUNET_break (0); /* integer overflow */ | ||
696 | return GNUNET_SYSERR; | ||
697 | } | ||
698 | if (size >= GNUNET_MAX_MALLOC_CHECKED) | ||
699 | { | ||
700 | /* too large to be processed */ | ||
701 | return GNUNET_SYSERR; | ||
702 | } | ||
703 | ent = GNUNET_malloc (size); | ||
704 | mdata = (char *) &ent[md->item_count]; | ||
705 | off = size - (md->item_count * sizeof(struct MetaDataEntry)); | ||
706 | i = 0; | ||
707 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
708 | { | ||
709 | ent[i].type = htonl ((uint32_t) pos->type); | ||
710 | ent[i].format = htonl ((uint32_t) pos->format); | ||
711 | ent[i].data_size = htonl ((uint32_t) pos->data_size); | ||
712 | if (NULL == pos->plugin_name) | ||
713 | plen = 0; | ||
714 | else | ||
715 | plen = strlen (pos->plugin_name) + 1; | ||
716 | ent[i].plugin_name_len = htonl ((uint32_t) plen); | ||
717 | if (NULL == pos->mime_type) | ||
718 | mlen = 0; | ||
719 | else | ||
720 | mlen = strlen (pos->mime_type) + 1; | ||
721 | ent[i].mime_type_len = htonl ((uint32_t) mlen); | ||
722 | off -= pos->data_size; | ||
723 | if ((EXTRACTOR_METAFORMAT_UTF8 == pos->format) || | ||
724 | (EXTRACTOR_METAFORMAT_C_STRING == pos->format)) | ||
725 | GNUNET_break ('\0' == pos->data[pos->data_size - 1]); | ||
726 | GNUNET_memcpy (&mdata[off], pos->data, pos->data_size); | ||
727 | off -= plen; | ||
728 | if (NULL != pos->plugin_name) | ||
729 | GNUNET_memcpy (&mdata[off], pos->plugin_name, plen); | ||
730 | off -= mlen; | ||
731 | if (NULL != pos->mime_type) | ||
732 | GNUNET_memcpy (&mdata[off], pos->mime_type, mlen); | ||
733 | i++; | ||
734 | } | ||
735 | GNUNET_assert (0 == off); | ||
736 | |||
737 | clen = 0; | ||
738 | cdata = NULL; | ||
739 | left = size; | ||
740 | i = 0; | ||
741 | for (pos = md->items_head; NULL != pos; pos = pos->next) | ||
742 | { | ||
743 | comp = GNUNET_NO; | ||
744 | if (0 == (opt & GNUNET_FS_META_DATA_SERIALIZE_NO_COMPRESS)) | ||
745 | comp = GNUNET_try_compression ((const char *) &ent[i], | ||
746 | left, | ||
747 | &cdata, | ||
748 | &clen); | ||
749 | |||
750 | if ((NULL == md->sbuf) && (0 == i)) | ||
751 | { | ||
752 | /* fill 'sbuf'; this "modifies" md, but since this is only | ||
753 | * an internal cache we will cast away the 'const' instead | ||
754 | * of making the API look strange. */ | ||
755 | vmd = (struct GNUNET_FS_MetaData *) md; | ||
756 | hdr = GNUNET_malloc (left + sizeof(struct MetaDataHeader)); | ||
757 | hdr->size = htonl (left); | ||
758 | hdr->entries = htonl (md->item_count); | ||
759 | if (GNUNET_YES == comp) | ||
760 | { | ||
761 | GNUNET_assert (clen < left); | ||
762 | hdr->version = htonl (2 | HEADER_COMPRESSED); | ||
763 | GNUNET_memcpy (&hdr[1], cdata, clen); | ||
764 | vmd->sbuf_size = clen + sizeof(struct MetaDataHeader); | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | hdr->version = htonl (2); | ||
769 | GNUNET_memcpy (&hdr[1], &ent[0], left); | ||
770 | vmd->sbuf_size = left + sizeof(struct MetaDataHeader); | ||
771 | } | ||
772 | vmd->sbuf = (char *) hdr; | ||
773 | } | ||
774 | |||
775 | if (((left + sizeof(struct MetaDataHeader)) <= max) || | ||
776 | ((GNUNET_YES == comp) && (clen <= max))) | ||
777 | { | ||
778 | /* success, this now fits! */ | ||
779 | if (GNUNET_YES == comp) | ||
780 | { | ||
781 | if (NULL == dst) | ||
782 | dst = GNUNET_malloc (clen + sizeof(struct MetaDataHeader)); | ||
783 | hdr = (struct MetaDataHeader *) dst; | ||
784 | hdr->version = htonl (2 | HEADER_COMPRESSED); | ||
785 | hdr->size = htonl (left); | ||
786 | hdr->entries = htonl (md->item_count - i); | ||
787 | GNUNET_memcpy (&dst[sizeof(struct MetaDataHeader)], cdata, clen); | ||
788 | GNUNET_free (cdata); | ||
789 | cdata = NULL; | ||
790 | GNUNET_free (ent); | ||
791 | rlen = clen + sizeof(struct MetaDataHeader); | ||
792 | } | ||
793 | else | ||
794 | { | ||
795 | if (NULL == dst) | ||
796 | dst = GNUNET_malloc (left + sizeof(struct MetaDataHeader)); | ||
797 | hdr = (struct MetaDataHeader *) dst; | ||
798 | hdr->version = htonl (2); | ||
799 | hdr->entries = htonl (md->item_count - i); | ||
800 | hdr->size = htonl (left); | ||
801 | GNUNET_memcpy (&dst[sizeof(struct MetaDataHeader)], &ent[i], left); | ||
802 | GNUNET_free (ent); | ||
803 | rlen = left + sizeof(struct MetaDataHeader); | ||
804 | } | ||
805 | if (NULL != *target) | ||
806 | { | ||
807 | if (GNUNET_YES == comp) | ||
808 | GNUNET_memcpy (*target, dst, clen + sizeof(struct MetaDataHeader)); | ||
809 | else | ||
810 | GNUNET_memcpy (*target, dst, left + sizeof(struct MetaDataHeader)); | ||
811 | GNUNET_free (dst); | ||
812 | } | ||
813 | else | ||
814 | { | ||
815 | *target = dst; | ||
816 | } | ||
817 | return rlen; | ||
818 | } | ||
819 | |||
820 | if (0 == (opt & GNUNET_FS_META_DATA_SERIALIZE_PART)) | ||
821 | { | ||
822 | /* does not fit! */ | ||
823 | GNUNET_free (ent); | ||
824 | if (NULL != cdata) | ||
825 | GNUNET_free (cdata); | ||
826 | cdata = NULL; | ||
827 | return GNUNET_SYSERR; | ||
828 | } | ||
829 | |||
830 | /* next iteration: ignore the corresponding meta data at the | ||
831 | * end and try again without it */ | ||
832 | left -= sizeof(struct MetaDataEntry); | ||
833 | left -= pos->data_size; | ||
834 | if (NULL != pos->plugin_name) | ||
835 | left -= strlen (pos->plugin_name) + 1; | ||
836 | if (NULL != pos->mime_type) | ||
837 | left -= strlen (pos->mime_type) + 1; | ||
838 | |||
839 | if (NULL != cdata) | ||
840 | GNUNET_free (cdata); | ||
841 | cdata = NULL; | ||
842 | i++; | ||
843 | } | ||
844 | GNUNET_free (ent); | ||
845 | |||
846 | /* nothing fit, only write header! */ | ||
847 | ihdr.version = htonl (2); | ||
848 | ihdr.entries = htonl (0); | ||
849 | ihdr.size = htonl (0); | ||
850 | if (NULL == *target) | ||
851 | *target = (char *) GNUNET_new (struct MetaDataHeader); | ||
852 | GNUNET_memcpy (*target, &ihdr, sizeof(struct MetaDataHeader)); | ||
853 | return sizeof(struct MetaDataHeader); | ||
854 | } | ||
855 | |||
856 | |||
857 | ssize_t | ||
858 | GNUNET_FS_meta_data_get_serialized_size (const struct | ||
859 | GNUNET_FS_MetaData *md) | ||
860 | { | ||
861 | ssize_t ret; | ||
862 | char *ptr; | ||
863 | |||
864 | if (NULL != md->sbuf) | ||
865 | return md->sbuf_size; | ||
866 | ptr = NULL; | ||
867 | ret = | ||
868 | GNUNET_FS_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED, | ||
869 | GNUNET_FS_META_DATA_SERIALIZE_FULL); | ||
870 | if (-1 != ret) | ||
871 | GNUNET_free (ptr); | ||
872 | return ret; | ||
873 | } | ||
874 | |||
875 | |||
876 | /** | ||
877 | * Deserialize meta-data. Initializes md. | ||
878 | * | ||
879 | * @param input buffer with the serialized metadata | ||
880 | * @param size number of bytes available in input | ||
881 | * @return MD on success, NULL on error (i.e. | ||
882 | * bad format) | ||
883 | */ | ||
884 | struct GNUNET_FS_MetaData * | ||
885 | GNUNET_FS_meta_data_deserialize (const char *input, size_t size) | ||
886 | { | ||
887 | struct GNUNET_FS_MetaData *md; | ||
888 | struct MetaDataHeader hdr; | ||
889 | struct MetaDataEntry ent; | ||
890 | uint32_t ic; | ||
891 | uint32_t i; | ||
892 | char *data; | ||
893 | const char *cdata; | ||
894 | uint32_t version; | ||
895 | uint32_t dataSize; | ||
896 | int compressed; | ||
897 | size_t left; | ||
898 | uint32_t mlen; | ||
899 | uint32_t plen; | ||
900 | uint32_t dlen; | ||
901 | const char *mdata; | ||
902 | const char *meta_data; | ||
903 | const char *plugin_name; | ||
904 | const char *mime_type; | ||
905 | enum EXTRACTOR_MetaFormat format; | ||
906 | |||
907 | if (size < sizeof(struct MetaDataHeader)) | ||
908 | return NULL; | ||
909 | GNUNET_memcpy (&hdr, input, sizeof(struct MetaDataHeader)); | ||
910 | version = ntohl (hdr.version) & HEADER_VERSION_MASK; | ||
911 | compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0; | ||
912 | |||
913 | if (1 == version) | ||
914 | return NULL; /* null pointer */ | ||
915 | if (2 != version) | ||
916 | { | ||
917 | GNUNET_break_op (0); /* unsupported version */ | ||
918 | return NULL; | ||
919 | } | ||
920 | |||
921 | ic = ntohl (hdr.entries); | ||
922 | dataSize = ntohl (hdr.size); | ||
923 | if (((sizeof(struct MetaDataEntry) * ic) > dataSize) || | ||
924 | ((0 != ic) && | ||
925 | (dataSize / ic < sizeof(struct MetaDataEntry)))) | ||
926 | { | ||
927 | GNUNET_break_op (0); | ||
928 | return NULL; | ||
929 | } | ||
930 | |||
931 | if (compressed) | ||
932 | { | ||
933 | if (dataSize >= GNUNET_MAX_MALLOC_CHECKED) | ||
934 | { | ||
935 | /* make sure we don't blow our memory limit because of a mal-formed | ||
936 | * message... */ | ||
937 | GNUNET_break_op (0); | ||
938 | return NULL; | ||
939 | } | ||
940 | data = | ||
941 | GNUNET_decompress ((const char *) &input[sizeof(struct MetaDataHeader)], | ||
942 | size - sizeof(struct MetaDataHeader), | ||
943 | dataSize); | ||
944 | if (NULL == data) | ||
945 | { | ||
946 | GNUNET_break_op (0); | ||
947 | return NULL; | ||
948 | } | ||
949 | cdata = data; | ||
950 | } | ||
951 | else | ||
952 | { | ||
953 | data = NULL; | ||
954 | cdata = (const char *) &input[sizeof(struct MetaDataHeader)]; | ||
955 | if (dataSize != size - sizeof(struct MetaDataHeader)) | ||
956 | { | ||
957 | GNUNET_break_op (0); | ||
958 | return NULL; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | md = GNUNET_FS_meta_data_create (); | ||
963 | left = dataSize - ic * sizeof(struct MetaDataEntry); | ||
964 | mdata = &cdata[ic * sizeof(struct MetaDataEntry)]; | ||
965 | for (i = 0; i < ic; i++) | ||
966 | { | ||
967 | GNUNET_memcpy (&ent, &cdata[i * sizeof(struct MetaDataEntry)], | ||
968 | sizeof(struct MetaDataEntry)); | ||
969 | format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format); | ||
970 | if ((EXTRACTOR_METAFORMAT_UTF8 != format) && | ||
971 | (EXTRACTOR_METAFORMAT_C_STRING != format) && | ||
972 | (EXTRACTOR_METAFORMAT_BINARY != format)) | ||
973 | { | ||
974 | GNUNET_break_op (0); | ||
975 | break; | ||
976 | } | ||
977 | dlen = ntohl (ent.data_size); | ||
978 | plen = ntohl (ent.plugin_name_len); | ||
979 | mlen = ntohl (ent.mime_type_len); | ||
980 | if (dlen > left) | ||
981 | { | ||
982 | GNUNET_break_op (0); | ||
983 | break; | ||
984 | } | ||
985 | left -= dlen; | ||
986 | meta_data = &mdata[left]; | ||
987 | if ((EXTRACTOR_METAFORMAT_UTF8 == format) || | ||
988 | (EXTRACTOR_METAFORMAT_C_STRING == format)) | ||
989 | { | ||
990 | if (0 == dlen) | ||
991 | { | ||
992 | GNUNET_break_op (0); | ||
993 | break; | ||
994 | } | ||
995 | if ('\0' != meta_data[dlen - 1]) | ||
996 | { | ||
997 | GNUNET_break_op (0); | ||
998 | break; | ||
999 | } | ||
1000 | } | ||
1001 | if (plen > left) | ||
1002 | { | ||
1003 | GNUNET_break_op (0); | ||
1004 | break; | ||
1005 | } | ||
1006 | left -= plen; | ||
1007 | if ((plen > 0) && ('\0' != mdata[left + plen - 1])) | ||
1008 | { | ||
1009 | GNUNET_break_op (0); | ||
1010 | break; | ||
1011 | } | ||
1012 | if (0 == plen) | ||
1013 | plugin_name = NULL; | ||
1014 | else | ||
1015 | plugin_name = &mdata[left]; | ||
1016 | |||
1017 | if (mlen > left) | ||
1018 | { | ||
1019 | GNUNET_break_op (0); | ||
1020 | break; | ||
1021 | } | ||
1022 | left -= mlen; | ||
1023 | if ((mlen > 0) && ('\0' != mdata[left + mlen - 1])) | ||
1024 | { | ||
1025 | GNUNET_break_op (0); | ||
1026 | break; | ||
1027 | } | ||
1028 | if (0 == mlen) | ||
1029 | mime_type = NULL; | ||
1030 | else | ||
1031 | mime_type = &mdata[left]; | ||
1032 | GNUNET_FS_meta_data_insert (md, plugin_name, | ||
1033 | (enum EXTRACTOR_MetaType) | ||
1034 | ntohl (ent.type), format, mime_type, | ||
1035 | meta_data, dlen); | ||
1036 | } | ||
1037 | GNUNET_free (data); | ||
1038 | return md; | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | /** | ||
1043 | * Read a metadata container. | ||
1044 | * | ||
1045 | * @param h handle to an open file | ||
1046 | * @param what describes what is being read (for error message creation) | ||
1047 | * @param result the buffer to store a pointer to the (allocated) metadata | ||
1048 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
1049 | */ | ||
1050 | enum GNUNET_GenericReturnValue | ||
1051 | GNUNET_FS_read_meta_data (struct GNUNET_BIO_ReadHandle *h, | ||
1052 | const char *what, | ||
1053 | struct GNUNET_FS_MetaData **result) | ||
1054 | { | ||
1055 | uint32_t size; | ||
1056 | char *buf; | ||
1057 | char *emsg; | ||
1058 | struct GNUNET_FS_MetaData *meta; | ||
1059 | |||
1060 | if (GNUNET_OK != GNUNET_BIO_read_int32 (h, | ||
1061 | _ ("metadata length"), | ||
1062 | (int32_t *) &size)) | ||
1063 | return GNUNET_SYSERR; | ||
1064 | if (0 == size) | ||
1065 | { | ||
1066 | *result = NULL; | ||
1067 | return GNUNET_OK; | ||
1068 | } | ||
1069 | if (MAX_META_DATA < size) | ||
1070 | { | ||
1071 | GNUNET_asprintf (&emsg, | ||
1072 | _ ( | ||
1073 | "Serialized metadata `%s' larger than allowed (%u > %u)\n"), | ||
1074 | what, | ||
1075 | size, | ||
1076 | MAX_META_DATA); | ||
1077 | GNUNET_BIO_read_set_error (h, emsg); | ||
1078 | GNUNET_free (emsg); | ||
1079 | return GNUNET_SYSERR; | ||
1080 | } | ||
1081 | buf = GNUNET_malloc (size); | ||
1082 | if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size)) | ||
1083 | { | ||
1084 | GNUNET_free (buf); | ||
1085 | return GNUNET_SYSERR; | ||
1086 | } | ||
1087 | meta = GNUNET_FS_meta_data_deserialize (buf, size); | ||
1088 | if (NULL == meta) | ||
1089 | { | ||
1090 | GNUNET_free (buf); | ||
1091 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1092 | _ ("Failed to deserialize metadata `%s'"), what); | ||
1093 | return GNUNET_SYSERR; | ||
1094 | } | ||
1095 | GNUNET_free (buf); | ||
1096 | *result = meta; | ||
1097 | return GNUNET_OK; | ||
1098 | } | ||
1099 | |||
1100 | |||
1101 | /** | ||
1102 | * Write a metadata container. | ||
1103 | * | ||
1104 | * @param h the IO handle to write to | ||
1105 | * @param what what is being written (for error message creation) | ||
1106 | * @param m metadata to write | ||
1107 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1108 | */ | ||
1109 | enum GNUNET_GenericReturnValue | ||
1110 | GNUNET_FS_write_meta_data (struct GNUNET_BIO_WriteHandle *h, | ||
1111 | const char *what, | ||
1112 | const struct GNUNET_FS_MetaData *m) | ||
1113 | { | ||
1114 | ssize_t size; | ||
1115 | char *buf; | ||
1116 | |||
1117 | if (m == NULL) | ||
1118 | return GNUNET_BIO_write_int32 (h, _ ("metadata length"), 0); | ||
1119 | buf = NULL; | ||
1120 | size = GNUNET_FS_meta_data_serialize (m, | ||
1121 | &buf, | ||
1122 | MAX_META_DATA, | ||
1123 | GNUNET_FS_META_DATA_SERIALIZE_PART); | ||
1124 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1125 | "Serialized %lld bytes of metadata", | ||
1126 | (long long) size); | ||
1127 | |||
1128 | if (-1 == size) | ||
1129 | { | ||
1130 | GNUNET_free (buf); | ||
1131 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1132 | "Failed to serialize metadata `%s'", | ||
1133 | what); | ||
1134 | return GNUNET_SYSERR; | ||
1135 | } | ||
1136 | if ( (GNUNET_OK != | ||
1137 | GNUNET_BIO_write_int32 (h, | ||
1138 | "metadata length", | ||
1139 | (uint32_t) size)) || | ||
1140 | (GNUNET_OK != | ||
1141 | GNUNET_BIO_write (h, | ||
1142 | what, | ||
1143 | buf, | ||
1144 | size)) ) | ||
1145 | { | ||
1146 | GNUNET_free (buf); | ||
1147 | return GNUNET_SYSERR; | ||
1148 | } | ||
1149 | GNUNET_free (buf); | ||
1150 | return GNUNET_OK; | ||
1151 | } | ||
1152 | |||
1153 | |||
1154 | /** | ||
1155 | * Function used internally to read a metadata container from within a read | ||
1156 | * spec. | ||
1157 | * | ||
1158 | * @param cls ignored, always NULL | ||
1159 | * @param h the IO handle to read from | ||
1160 | * @param what what is being read (for error message creation) | ||
1161 | * @param target where to store the data | ||
1162 | * @param target_size ignored | ||
1163 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1164 | */ | ||
1165 | static int | ||
1166 | read_spec_handler_meta_data (void *cls, | ||
1167 | struct GNUNET_BIO_ReadHandle *h, | ||
1168 | const char *what, | ||
1169 | void *target, | ||
1170 | size_t target_size) | ||
1171 | { | ||
1172 | struct GNUNET_FS_MetaData **result = target; | ||
1173 | return GNUNET_FS_read_meta_data (h, what, result); | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | /** | ||
1178 | * Create the specification to read a metadata container. | ||
1179 | * | ||
1180 | * @param what describes what is being read (for error message creation) | ||
1181 | * @param result the buffer to store a pointer to the (allocated) metadata | ||
1182 | * @return the read spec | ||
1183 | */ | ||
1184 | struct GNUNET_BIO_ReadSpec | ||
1185 | GNUNET_FS_read_spec_meta_data (const char *what, | ||
1186 | struct GNUNET_FS_MetaData **result) | ||
1187 | { | ||
1188 | struct GNUNET_BIO_ReadSpec rs = { | ||
1189 | .rh = &read_spec_handler_meta_data, | ||
1190 | .cls = NULL, | ||
1191 | .target = result, | ||
1192 | .size = 0, | ||
1193 | }; | ||
1194 | |||
1195 | return rs; | ||
1196 | } | ||
1197 | |||
1198 | |||
1199 | /** | ||
1200 | * Function used internally to write a metadata container from within a write | ||
1201 | * spec. | ||
1202 | * | ||
1203 | * @param cls ignored, always NULL | ||
1204 | * @param h the IO handle to write to | ||
1205 | * @param what what is being written (for error message creation) | ||
1206 | * @param source the data to write | ||
1207 | * @param source_size ignored | ||
1208 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
1209 | */ | ||
1210 | static int | ||
1211 | write_spec_handler_meta_data (void *cls, | ||
1212 | struct GNUNET_BIO_WriteHandle *h, | ||
1213 | const char *what, | ||
1214 | void *source, | ||
1215 | size_t source_size) | ||
1216 | { | ||
1217 | const struct GNUNET_FS_MetaData *m = source; | ||
1218 | return GNUNET_FS_write_meta_data (h, what, m); | ||
1219 | } | ||
1220 | |||
1221 | |||
1222 | struct GNUNET_BIO_WriteSpec | ||
1223 | GNUNET_FS_write_spec_meta_data (const char *what, | ||
1224 | const struct GNUNET_FS_MetaData *m) | ||
1225 | { | ||
1226 | struct GNUNET_BIO_WriteSpec ws = { | ||
1227 | .wh = &write_spec_handler_meta_data, | ||
1228 | .cls = NULL, | ||
1229 | .what = what, | ||
1230 | .source = (void *) m, | ||
1231 | .source_size = 0, | ||
1232 | }; | ||
1233 | |||
1234 | return ws; | ||
1235 | } | ||
1236 | |||
1237 | |||
1238 | /* end of meta_data.c */ | ||