diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-09-02 08:24:20 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-09-02 08:24:20 +0000 |
commit | 09118c85cd5200267784985900e4f83ea31b8622 (patch) | |
tree | 53fcbc1b6a38c3f4582769276243c485a7b98dff /src | |
parent | 815c76f4aeb141fa9654bc3abc16998c8188268f (diff) | |
download | gnunet-09118c85cd5200267784985900e4f83ea31b8622.tar.gz gnunet-09118c85cd5200267784985900e4f83ea31b8622.zip |
refactoring publishing code
Diffstat (limited to 'src')
-rw-r--r-- | src/fs/Makefile.am | 1 | ||||
-rw-r--r-- | src/fs/fs.h | 13 | ||||
-rw-r--r-- | src/fs/fs_file_information.c | 2 | ||||
-rw-r--r-- | src/fs/fs_publish.c | 450 | ||||
-rw-r--r-- | src/fs/fs_tree.c | 381 | ||||
-rw-r--r-- | src/fs/fs_tree.h | 167 |
6 files changed, 751 insertions, 263 deletions
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index ebe6790c9..d4da86e6d 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am | |||
@@ -23,6 +23,7 @@ libgnunetfs_la_SOURCES = \ | |||
23 | fs_publish.c \ | 23 | fs_publish.c \ |
24 | fs_namespace.c \ | 24 | fs_namespace.c \ |
25 | fs_search.c \ | 25 | fs_search.c \ |
26 | fs_tree.c fs_tree.h \ | ||
26 | fs_unindex.c \ | 27 | fs_unindex.c \ |
27 | fs_uri.c | 28 | fs_uri.c |
28 | 29 | ||
diff --git a/src/fs/fs.h b/src/fs/fs.h index 956048cc5..c8712b492 100644 --- a/src/fs/fs.h +++ b/src/fs/fs.h | |||
@@ -250,7 +250,12 @@ struct GNUNET_FS_FileInformation | |||
250 | * entries for the size of the file and | 250 | * entries for the size of the file and |
251 | * finally freed once the upload is complete. | 251 | * finally freed once the upload is complete. |
252 | */ | 252 | */ |
253 | struct ContentHashKey *chk_tree; | 253 | // struct ContentHashKey *chk_tree; |
254 | |||
255 | /** | ||
256 | * Encoder being used to publish this file. | ||
257 | */ | ||
258 | struct GNUNET_FS_TreeEncoder *te; | ||
254 | 259 | ||
255 | /** | 260 | /** |
256 | * Error message (non-NULL if this operation | 261 | * Error message (non-NULL if this operation |
@@ -261,20 +266,20 @@ struct GNUNET_FS_FileInformation | |||
261 | /** | 266 | /** |
262 | * Number of entries in "chk_tree". | 267 | * Number of entries in "chk_tree". |
263 | */ | 268 | */ |
264 | unsigned int chk_tree_depth; | 269 | // unsigned int chk_tree_depth; |
265 | 270 | ||
266 | /** | 271 | /** |
267 | * Depth in the CHK-tree at which we are | 272 | * Depth in the CHK-tree at which we are |
268 | * currently publishing. 0 is the root | 273 | * currently publishing. 0 is the root |
269 | * of the tree. | 274 | * of the tree. |
270 | */ | 275 | */ |
271 | unsigned int current_depth; | 276 | // unsigned int current_depth; |
272 | 277 | ||
273 | /** | 278 | /** |
274 | * How many bytes of this file or directory have been | 279 | * How many bytes of this file or directory have been |
275 | * published so far? | 280 | * published so far? |
276 | */ | 281 | */ |
277 | uint64_t publish_offset; | 282 | // uint64_t publish_offset; |
278 | 283 | ||
279 | /** | 284 | /** |
280 | * Data describing either the file or the directory. | 285 | * Data describing either the file or the directory. |
diff --git a/src/fs/fs_file_information.c b/src/fs/fs_file_information.c index 984d56f30..5de9cbeb8 100644 --- a/src/fs/fs_file_information.c +++ b/src/fs/fs_file_information.c | |||
@@ -701,7 +701,6 @@ GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, | |||
701 | ent->next = dir->data.dir.entries; | 701 | ent->next = dir->data.dir.entries; |
702 | dir->data.dir.entries = ent; | 702 | dir->data.dir.entries = ent; |
703 | dir->data.dir.dir_size = 0; | 703 | dir->data.dir.dir_size = 0; |
704 | dir->publish_offset = 0; | ||
705 | GNUNET_FS_file_information_sync (ent); | 704 | GNUNET_FS_file_information_sync (ent); |
706 | GNUNET_FS_file_information_sync (dir); | 705 | GNUNET_FS_file_information_sync (dir); |
707 | return GNUNET_OK; | 706 | return GNUNET_OK; |
@@ -824,7 +823,6 @@ GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, | |||
824 | &fi->client_info); | 823 | &fi->client_info); |
825 | } | 824 | } |
826 | GNUNET_free_non_null (fi->emsg); | 825 | GNUNET_free_non_null (fi->emsg); |
827 | GNUNET_free_non_null (fi->chk_tree); | ||
828 | /* clean up serialization */ | 826 | /* clean up serialization */ |
829 | if (0 != UNLINK (fi->serialization)) | 827 | if (0 != UNLINK (fi->serialization)) |
830 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | 828 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, |
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c index 0c950f38a..6080fae03 100644 --- a/src/fs/fs_publish.c +++ b/src/fs/fs_publish.c | |||
@@ -26,8 +26,8 @@ | |||
26 | * @author Christian Grothoff | 26 | * @author Christian Grothoff |
27 | * | 27 | * |
28 | * TODO: | 28 | * TODO: |
29 | * - code-sharing with unindex (write unindex code, clean up new FIXME's) | ||
29 | * - indexing cleanup: unindex on failure (can wait) | 30 | * - indexing cleanup: unindex on failure (can wait) |
30 | * - code-sharing with unindex (can wait) | ||
31 | * - persistence support (can wait) | 31 | * - persistence support (can wait) |
32 | * - datastore reservation support (optimization) | 32 | * - datastore reservation support (optimization) |
33 | * - location URIs (publish with anonymity-level zero) | 33 | * - location URIs (publish with anonymity-level zero) |
@@ -39,6 +39,7 @@ | |||
39 | #include "gnunet_util_lib.h" | 39 | #include "gnunet_util_lib.h" |
40 | #include "gnunet_fs_service.h" | 40 | #include "gnunet_fs_service.h" |
41 | #include "fs.h" | 41 | #include "fs.h" |
42 | #include "fs_tree.h" | ||
42 | 43 | ||
43 | #define DEBUG_PUBLISH GNUNET_YES | 44 | #define DEBUG_PUBLISH GNUNET_YES |
44 | 45 | ||
@@ -110,12 +111,14 @@ make_publish_status (struct GNUNET_FS_ProgressInfo *pi, | |||
110 | = (NULL == p->dir) ? NULL : p->dir->client_info; | 111 | = (NULL == p->dir) ? NULL : p->dir->client_info; |
111 | pi->value.publish.size | 112 | pi->value.publish.size |
112 | = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size; | 113 | = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size; |
114 | #if FIXME | ||
113 | pi->value.publish.eta | 115 | pi->value.publish.eta |
114 | = GNUNET_TIME_calculate_eta (p->start_time, | 116 | = GNUNET_TIME_calculate_eta (p->start_time, |
115 | p->publish_offset, | 117 | p->publish_offset, |
116 | pi->value.publish.size); | 118 | pi->value.publish.size); |
117 | pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (p->start_time); | ||
118 | pi->value.publish.completed = p->publish_offset; | 119 | pi->value.publish.completed = p->publish_offset; |
120 | #endif | ||
121 | pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (p->start_time); | ||
119 | pi->value.publish.anonymity = p->anonymity; | 122 | pi->value.publish.anonymity = p->anonymity; |
120 | } | 123 | } |
121 | 124 | ||
@@ -302,7 +305,8 @@ publish_sblock (struct GNUNET_FS_PublishContext *sc) | |||
302 | * the result and continue the larger | 305 | * the result and continue the larger |
303 | * upload. | 306 | * upload. |
304 | * | 307 | * |
305 | * @param cls the "struct GNUNET_FS_PublishContext*" of the larger upload | 308 | * @param cls the "struct GNUNET_FS_PublishContext*" |
309 | * of the larger upload | ||
306 | * @param uri URI of the published blocks | 310 | * @param uri URI of the published blocks |
307 | * @param emsg NULL on success, otherwise error message | 311 | * @param emsg NULL on success, otherwise error message |
308 | */ | 312 | */ |
@@ -346,98 +350,198 @@ publish_kblocks_cont (void *cls, | |||
346 | } | 350 | } |
347 | 351 | ||
348 | 352 | ||
349 | /** | 353 | // FIXME: document |
350 | * Compute the depth of the CHK tree. | 354 | static size_t |
351 | * | 355 | block_reader (void *cls, |
352 | * @param flen file length for which to compute the depth | 356 | uint64_t offset, |
353 | * @return depth of the tree | 357 | size_t max, |
354 | */ | 358 | void *buf, |
355 | static unsigned int | 359 | char **emsg) |
356 | compute_depth (uint64_t flen) | ||
357 | { | 360 | { |
358 | unsigned int treeDepth; | 361 | struct GNUNET_FS_PublishContext *sc = cls; |
359 | uint64_t fl; | 362 | struct GNUNET_FS_FileInformation *p; |
363 | uint16_t pt_size; | ||
364 | const char *dd; | ||
365 | |||
366 | p = sc->fi_pos; | ||
367 | if (p->is_directory) | ||
368 | { | ||
369 | pt_size = GNUNET_MIN(max, | ||
370 | p->data.dir.dir_size - offset); | ||
371 | dd = p->data.dir.dir_data; | ||
372 | memcpy (&buf, | ||
373 | &dd[offset], | ||
374 | pt_size); | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | pt_size = GNUNET_MIN(max, | ||
379 | p->data.file.file_size - offset); | ||
380 | if (pt_size != | ||
381 | p->data.file.reader (p->data.file.reader_cls, | ||
382 | offset, | ||
383 | pt_size, | ||
384 | buf, | ||
385 | emsg)) | ||
386 | return 0; | ||
387 | } | ||
388 | return pt_size; | ||
389 | } | ||
360 | 390 | ||
361 | treeDepth = 1; | 391 | |
362 | fl = DBLOCK_SIZE; | 392 | // FIXME: document |
363 | while (fl < flen) | 393 | static void |
394 | encode_cont (void *cls, | ||
395 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
396 | { | ||
397 | struct GNUNET_FS_PublishContext *sc = cls; | ||
398 | struct GNUNET_FS_FileInformation *p; | ||
399 | struct GNUNET_FS_ProgressInfo pi; | ||
400 | char *emsg; | ||
401 | |||
402 | p = sc->fi_pos; | ||
403 | GNUNET_FS_tree_encoder_finish (p->te, | ||
404 | &p->chk_uri, | ||
405 | &emsg); | ||
406 | p->te = NULL; | ||
407 | if (NULL != emsg) | ||
364 | { | 408 | { |
365 | treeDepth++; | 409 | GNUNET_asprintf (&p->emsg, |
366 | if (fl * CHK_PER_INODE < fl) | 410 | _("Upload failed: %s"), |
367 | { | 411 | emsg); |
368 | /* integer overflow, this is a HUGE file... */ | 412 | GNUNET_free (emsg); |
369 | return treeDepth; | 413 | GNUNET_FS_file_information_sync (p); |
370 | } | 414 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; |
371 | fl = fl * CHK_PER_INODE; | 415 | make_publish_status (&pi, sc, p); |
416 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
417 | pi.value.publish.specifics.error.message = p->emsg; | ||
418 | p->client_info | ||
419 | = sc->h->upcb (sc->h->upcb_cls, | ||
420 | &pi); | ||
372 | } | 421 | } |
373 | return treeDepth; | 422 | /* continue with main */ |
423 | sc->upload_task | ||
424 | = GNUNET_SCHEDULER_add_delayed (sc->h->sched, | ||
425 | GNUNET_NO, | ||
426 | GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
427 | GNUNET_SCHEDULER_NO_TASK, | ||
428 | GNUNET_TIME_UNIT_ZERO, | ||
429 | &do_upload, | ||
430 | sc); | ||
374 | } | 431 | } |
375 | 432 | ||
376 | 433 | ||
377 | /** | 434 | /** |
378 | * Compute the size of the current IBlock. | 435 | * Function called asking for the current (encoded) |
436 | * block to be processed. After processing the | ||
437 | * client should either call "GNUNET_FS_tree_encode_next" | ||
438 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
379 | * | 439 | * |
380 | * @param height height of the IBlock in the tree (aka overall | 440 | * @param cls closure |
381 | * number of tree levels minus depth); 0 == DBlock | 441 | * @param query the query for the block (key for lookup in the datastore) |
382 | * @param offset current offset in the overall file | 442 | * @param type type of the block (IBLOCK or DBLOCK) |
383 | * @return size of the corresponding IBlock | 443 | * @param block the (encrypted) block |
444 | * @param block_size size of block (in bytes) | ||
384 | */ | 445 | */ |
385 | static uint16_t | 446 | static void |
386 | compute_iblock_size (unsigned int height, | 447 | block_proc (void *cls, |
387 | uint64_t offset) | 448 | const GNUNET_HashCode *query, |
449 | uint64_t offset, | ||
450 | unsigned int type, | ||
451 | const void *block, | ||
452 | uint16_t block_size) | ||
388 | { | 453 | { |
389 | unsigned int ret; | 454 | struct GNUNET_FS_PublishContext *sc = cls; |
390 | unsigned int i; | 455 | struct GNUNET_FS_FileInformation *p; |
391 | uint64_t mod; | 456 | struct PutContCtx * dpc_cls; |
392 | uint64_t bds; | 457 | struct OnDemandBlock odb; |
393 | 458 | ||
394 | GNUNET_assert (height > 0); | 459 | p = sc->fi_pos; |
395 | bds = DBLOCK_SIZE; /* number of bytes each CHK at level "i" | 460 | if (NULL == sc->dsh) |
396 | corresponds to */ | ||
397 | for (i=0;i<height;i++) | ||
398 | bds *= CHK_PER_INODE; | ||
399 | mod = offset % bds; | ||
400 | if (0 == mod) | ||
401 | { | 461 | { |
402 | /* we were triggered at the end of a full block */ | 462 | sc->upload_task |
403 | ret = CHK_PER_INODE; | 463 | = GNUNET_SCHEDULER_add_delayed (sc->h->sched, |
464 | GNUNET_NO, | ||
465 | GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
466 | GNUNET_SCHEDULER_NO_TASK, | ||
467 | GNUNET_TIME_UNIT_ZERO, | ||
468 | &do_upload, | ||
469 | sc); | ||
470 | return; | ||
404 | } | 471 | } |
405 | else | 472 | |
473 | GNUNET_assert (GNUNET_NO == sc->in_network_wait); | ||
474 | sc->in_network_wait = GNUNET_YES; | ||
475 | dpc_cls = GNUNET_malloc(sizeof(struct PutContCtx)); | ||
476 | dpc_cls->cont = &do_upload; | ||
477 | dpc_cls->cont_cls = sc; | ||
478 | dpc_cls->p = p; | ||
479 | if ( (p->is_directory) && | ||
480 | (p->data.file.do_index) && | ||
481 | (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) ) | ||
406 | { | 482 | { |
407 | /* we were triggered at the end of the file */ | 483 | odb.offset = offset; |
408 | bds /= CHK_PER_INODE; | 484 | odb.file_id = p->data.file.file_id; |
409 | ret = mod / bds; | 485 | GNUNET_DATASTORE_put (sc->dsh, |
410 | if (0 != mod % bds) | 486 | sc->rid, |
411 | ret++; | 487 | query, |
488 | sizeof(struct OnDemandBlock), | ||
489 | &odb, | ||
490 | GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND, | ||
491 | p->priority, | ||
492 | p->anonymity, | ||
493 | p->expirationTime, | ||
494 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
495 | &ds_put_cont, | ||
496 | dpc_cls); | ||
497 | return; | ||
412 | } | 498 | } |
413 | return (uint16_t) (ret * sizeof(struct ContentHashKey)); | 499 | GNUNET_DATASTORE_put (sc->dsh, |
500 | sc->rid, | ||
501 | query, | ||
502 | block_size, | ||
503 | block, | ||
504 | type, | ||
505 | p->priority, | ||
506 | p->anonymity, | ||
507 | p->expirationTime, | ||
508 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
509 | &ds_put_cont, | ||
510 | dpc_cls); | ||
414 | } | 511 | } |
415 | 512 | ||
416 | 513 | ||
417 | /** | 514 | /** |
418 | * Compute the offset of the CHK for the | 515 | * Function called with information about our |
419 | * current block in the IBlock above. | 516 | * progress in computing the tree encoding. |
420 | * | 517 | * |
421 | * @param height height of the IBlock in the tree (aka overall | 518 | * @param cls closure |
422 | * number of tree levels minus depth); 0 == DBlock | 519 | * @param offset where are we in the file |
423 | * @param offset current offset in the overall file | 520 | * @param pt_block plaintext of the currently processed block |
424 | * @return (array of CHKs') offset in the above IBlock | 521 | * @param pt_size size of pt_block |
522 | * @param depth depth of the block in the tree | ||
425 | */ | 523 | */ |
426 | static unsigned int | 524 | static void |
427 | compute_chk_offset (unsigned int height, | 525 | progress_proc (void *cls, |
428 | uint64_t offset) | 526 | uint64_t offset, |
429 | { | 527 | const void *pt_block, |
430 | uint64_t bds; | 528 | size_t pt_size, |
431 | unsigned int ret; | 529 | unsigned int depth) |
432 | unsigned int i; | 530 | { |
531 | struct GNUNET_FS_PublishContext *sc = cls; | ||
532 | struct GNUNET_FS_FileInformation *p; | ||
533 | struct GNUNET_FS_ProgressInfo pi; | ||
433 | 534 | ||
434 | bds = DBLOCK_SIZE; /* number of bytes each CHK at level "i" | 535 | p = sc->fi_pos; |
435 | corresponds to */ | 536 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; |
436 | for (i=0;i<height;i++) | 537 | make_publish_status (&pi, sc, p); |
437 | bds *= CHK_PER_INODE; | 538 | pi.value.publish.specifics.progress.data = pt_block; |
438 | GNUNET_assert (0 == (offset % bds)); | 539 | pi.value.publish.specifics.progress.offset = offset; |
439 | ret = offset / bds; | 540 | pi.value.publish.specifics.progress.data_len = pt_size; |
440 | return ret % CHK_PER_INODE; | 541 | // FIXME: add depth to pi |
542 | p->client_info | ||
543 | = sc->h->upcb (sc->h->upcb_cls, | ||
544 | &pi); | ||
441 | } | 545 | } |
442 | 546 | ||
443 | 547 | ||
@@ -450,32 +554,18 @@ compute_chk_offset (unsigned int height, | |||
450 | * @param p specific file or directory for which kblocks | 554 | * @param p specific file or directory for which kblocks |
451 | * should be created | 555 | * should be created |
452 | */ | 556 | */ |
557 | // FIXME: "p" argument is not needed! | ||
453 | static void | 558 | static void |
454 | publish_content (struct GNUNET_FS_PublishContext *sc, | 559 | publish_content (struct GNUNET_FS_PublishContext *sc, |
455 | struct GNUNET_FS_FileInformation *p) | 560 | struct GNUNET_FS_FileInformation *p) |
456 | { | 561 | { |
457 | struct GNUNET_FS_ProgressInfo pi; | ||
458 | struct ContentHashKey *mychk; | ||
459 | const void *pt_block; | ||
460 | uint16_t pt_size; | ||
461 | char *emsg; | 562 | char *emsg; |
462 | char iob[DBLOCK_SIZE]; | ||
463 | char enc[DBLOCK_SIZE]; | ||
464 | struct GNUNET_CRYPTO_AesSessionKey sk; | ||
465 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
466 | uint64_t size; | ||
467 | unsigned int off; | ||
468 | struct GNUNET_FS_DirectoryBuilder *db; | 563 | struct GNUNET_FS_DirectoryBuilder *db; |
469 | struct GNUNET_FS_FileInformation *dirpos; | 564 | struct GNUNET_FS_FileInformation *dirpos; |
470 | void *raw_data; | 565 | void *raw_data; |
471 | char *dd; | 566 | uint64_t size; |
472 | struct PutContCtx * dpc_cls; | ||
473 | struct OnDemandBlock odb; | ||
474 | 567 | ||
475 | // FIXME: figure out how to share this code | 568 | if (NULL == p->te) |
476 | // with unindex! | ||
477 | size = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size; | ||
478 | if (NULL == p->chk_tree) | ||
479 | { | 569 | { |
480 | if (p->is_directory) | 570 | if (p->is_directory) |
481 | { | 571 | { |
@@ -509,7 +599,7 @@ publish_content (struct GNUNET_FS_PublishContext *sc, | |||
509 | } | 599 | } |
510 | } | 600 | } |
511 | } | 601 | } |
512 | GNUNET_FS_directory_builder_add (db, | 602 | GNUNET_FS_directory_builder_add (db, |
513 | dirpos->chk_uri, | 603 | dirpos->chk_uri, |
514 | dirpos->meta, | 604 | dirpos->meta, |
515 | raw_data); | 605 | raw_data); |
@@ -519,177 +609,23 @@ publish_content (struct GNUNET_FS_PublishContext *sc, | |||
519 | GNUNET_FS_directory_builder_finish (db, | 609 | GNUNET_FS_directory_builder_finish (db, |
520 | &p->data.dir.dir_size, | 610 | &p->data.dir.dir_size, |
521 | &p->data.dir.dir_data); | 611 | &p->data.dir.dir_data); |
522 | size = p->data.dir.dir_size; | ||
523 | } | ||
524 | p->chk_tree_depth = compute_depth (size); | ||
525 | p->chk_tree = GNUNET_malloc (p->chk_tree_depth * | ||
526 | sizeof (struct ContentHashKey) * | ||
527 | CHK_PER_INODE); | ||
528 | p->current_depth = p->chk_tree_depth; | ||
529 | } | ||
530 | if (p->current_depth == p->chk_tree_depth) | ||
531 | { | ||
532 | if (p->is_directory) | ||
533 | { | ||
534 | pt_size = GNUNET_MIN(DBLOCK_SIZE, | ||
535 | p->data.dir.dir_size - p->publish_offset); | ||
536 | dd = p->data.dir.dir_data; | ||
537 | pt_block = &dd[p->publish_offset]; | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | pt_size = GNUNET_MIN(DBLOCK_SIZE, | ||
542 | p->data.file.file_size - p->publish_offset); | ||
543 | emsg = NULL; | ||
544 | if (pt_size != | ||
545 | p->data.file.reader (p->data.file.reader_cls, | ||
546 | p->publish_offset, | ||
547 | pt_size, | ||
548 | iob, | ||
549 | &emsg)) | ||
550 | { | ||
551 | GNUNET_asprintf (&p->emsg, | ||
552 | _("Upload failed: %s"), | ||
553 | emsg); | ||
554 | GNUNET_free (emsg); | ||
555 | GNUNET_FS_file_information_sync (p); | ||
556 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
557 | make_publish_status (&pi, sc, p); | ||
558 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
559 | pi.value.publish.specifics.error.message = p->emsg; | ||
560 | p->client_info | ||
561 | = sc->h->upcb (sc->h->upcb_cls, | ||
562 | &pi); | ||
563 | /* continue with main (to propagate error up) */ | ||
564 | sc->upload_task | ||
565 | = GNUNET_SCHEDULER_add_delayed (sc->h->sched, | ||
566 | GNUNET_NO, | ||
567 | GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
568 | GNUNET_SCHEDULER_NO_TASK, | ||
569 | GNUNET_TIME_UNIT_ZERO, | ||
570 | &do_upload, | ||
571 | sc); | ||
572 | return; | ||
573 | } | ||
574 | pt_block = iob; | ||
575 | } | 612 | } |
613 | size = (p->is_directory) | ||
614 | ? p->data.dir.dir_size | ||
615 | : p->data.file.file_size; | ||
616 | p->te = GNUNET_FS_tree_encoder_create (sc->h, | ||
617 | size, | ||
618 | sc, | ||
619 | &block_reader, | ||
620 | &block_proc, | ||
621 | &progress_proc, | ||
622 | &encode_cont); | ||
623 | |||
576 | } | 624 | } |
577 | else | 625 | GNUNET_FS_tree_encoder_next (p->te); |
578 | { | ||
579 | pt_size = compute_iblock_size (p->chk_tree_depth - p->current_depth, | ||
580 | p->publish_offset); | ||
581 | pt_block = &p->chk_tree[p->current_depth * | ||
582 | CHK_PER_INODE]; | ||
583 | } | ||
584 | off = compute_chk_offset (p->chk_tree_depth - p->current_depth, | ||
585 | p->publish_offset); | ||
586 | mychk = &p->chk_tree[(p->current_depth-1)*CHK_PER_INODE+off]; | ||
587 | GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key); | ||
588 | GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv); | ||
589 | GNUNET_CRYPTO_aes_encrypt (pt_block, | ||
590 | pt_size, | ||
591 | &sk, | ||
592 | &iv, | ||
593 | enc); | ||
594 | // NOTE: this block below is all that really differs | ||
595 | // between publish/unindex! Parameterize & move this code! | ||
596 | if (NULL == sc->dsh) | ||
597 | { | ||
598 | sc->upload_task | ||
599 | = GNUNET_SCHEDULER_add_delayed (sc->h->sched, | ||
600 | GNUNET_NO, | ||
601 | GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
602 | GNUNET_SCHEDULER_NO_TASK, | ||
603 | GNUNET_TIME_UNIT_ZERO, | ||
604 | &do_upload, | ||
605 | sc); | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | GNUNET_assert (GNUNET_NO == sc->in_network_wait); | ||
610 | sc->in_network_wait = GNUNET_YES; | ||
611 | dpc_cls = GNUNET_malloc(sizeof(struct PutContCtx)); | ||
612 | dpc_cls->cont = &do_upload; | ||
613 | dpc_cls->cont_cls = sc; | ||
614 | dpc_cls->p = p; | ||
615 | if ( (p->is_directory) && | ||
616 | (p->data.file.do_index) && | ||
617 | (p->current_depth == p->chk_tree_depth) ) | ||
618 | { | ||
619 | odb.offset = p->publish_offset; | ||
620 | odb.file_id = p->data.file.file_id; | ||
621 | GNUNET_DATASTORE_put (sc->dsh, | ||
622 | sc->rid, | ||
623 | &mychk->query, | ||
624 | sizeof(struct OnDemandBlock), | ||
625 | &odb, | ||
626 | GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND, | ||
627 | p->priority, | ||
628 | p->anonymity, | ||
629 | p->expirationTime, | ||
630 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
631 | &ds_put_cont, | ||
632 | dpc_cls); | ||
633 | } | ||
634 | else | ||
635 | { | ||
636 | GNUNET_DATASTORE_put (sc->dsh, | ||
637 | sc->rid, | ||
638 | &mychk->query, | ||
639 | pt_size, | ||
640 | enc, | ||
641 | (p->current_depth == p->chk_tree_depth) | ||
642 | ? GNUNET_DATASTORE_BLOCKTYPE_DBLOCK | ||
643 | : GNUNET_DATASTORE_BLOCKTYPE_IBLOCK, | ||
644 | p->priority, | ||
645 | p->anonymity, | ||
646 | p->expirationTime, | ||
647 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
648 | &ds_put_cont, | ||
649 | dpc_cls); | ||
650 | } | ||
651 | } | ||
652 | if (p->current_depth == p->chk_tree_depth) | ||
653 | { | ||
654 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; | ||
655 | make_publish_status (&pi, sc, p); | ||
656 | pi.value.publish.specifics.progress.data = pt_block; | ||
657 | pi.value.publish.specifics.progress.offset = p->publish_offset; | ||
658 | pi.value.publish.specifics.progress.data_len = pt_size; | ||
659 | p->client_info | ||
660 | = sc->h->upcb (sc->h->upcb_cls, | ||
661 | &pi); | ||
662 | } | ||
663 | GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query); | ||
664 | if (p->current_depth == p->chk_tree_depth) | ||
665 | { | ||
666 | p->publish_offset += pt_size; | ||
667 | if ( (p->publish_offset == size) || | ||
668 | (0 == p->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE) ) ) | ||
669 | p->current_depth--; | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | if ( (off == CHK_PER_INODE) || | ||
674 | (p->publish_offset == size) ) | ||
675 | p->current_depth--; | ||
676 | else | ||
677 | p->current_depth = p->chk_tree_depth; | ||
678 | } | ||
679 | if (0 == p->current_depth) | ||
680 | { | ||
681 | p->chk_uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri)); | ||
682 | p->chk_uri->type = chk; | ||
683 | p->chk_uri->data.chk.chk = p->chk_tree[0]; | ||
684 | p->chk_uri->data.chk.file_length = size; | ||
685 | GNUNET_free (p->chk_tree); | ||
686 | p->chk_tree = NULL; | ||
687 | } | ||
688 | } | 626 | } |
689 | 627 | ||
690 | 628 | ||
691 | |||
692 | |||
693 | /** | 629 | /** |
694 | * Process the response (or lack thereof) from | 630 | * Process the response (or lack thereof) from |
695 | * the "fs" service to our 'start index' request. | 631 | * the "fs" service to our 'start index' request. |
diff --git a/src/fs/fs_tree.c b/src/fs/fs_tree.c new file mode 100644 index 000000000..5d6a4f1d9 --- /dev/null +++ b/src/fs/fs_tree.c | |||
@@ -0,0 +1,381 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file fs/fs_tree.c | ||
22 | * @brief Merkle-tree-ish-CHK file encoding for GNUnet | ||
23 | * @see http://gnunet.org/encoding.php3 | ||
24 | * @author Krista Bennett | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * TODO: | ||
28 | * - decide if this API should be made public (gnunet_fs_service.h) | ||
29 | * or remain "internal" (but with exported symbols?) | ||
30 | */ | ||
31 | #include "platform.h" | ||
32 | #include "fs_tree.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Context for an ECRS-based file encoder that computes | ||
37 | * the Merkle-ish-CHK tree. | ||
38 | */ | ||
39 | struct GNUNET_FS_TreeEncoder | ||
40 | { | ||
41 | |||
42 | /** | ||
43 | * Global FS context. | ||
44 | */ | ||
45 | struct GNUNET_FS_Handle *h; | ||
46 | |||
47 | /** | ||
48 | * Closure for all callbacks. | ||
49 | */ | ||
50 | void *cls; | ||
51 | |||
52 | /** | ||
53 | * Function to call on encrypted blocks. | ||
54 | */ | ||
55 | GNUNET_FS_TreeBlockProcessor proc; | ||
56 | |||
57 | /** | ||
58 | * Function to call with progress information. | ||
59 | */ | ||
60 | GNUNET_FS_TreeProgressCallback progress; | ||
61 | |||
62 | /** | ||
63 | * Function to call to receive input data. | ||
64 | */ | ||
65 | GNUNET_FS_DataReader reader; | ||
66 | |||
67 | /** | ||
68 | * Function to call once we're done with processing. | ||
69 | */ | ||
70 | GNUNET_SCHEDULER_Task cont; | ||
71 | |||
72 | /** | ||
73 | * Set to an error message (if we had an error). | ||
74 | */ | ||
75 | char *emsg; | ||
76 | |||
77 | /** | ||
78 | * Set to the URI (upon successful completion) | ||
79 | */ | ||
80 | struct GNUNET_FS_Uri *uri; | ||
81 | |||
82 | /** | ||
83 | * Overall file size. | ||
84 | */ | ||
85 | uint64_t size; | ||
86 | |||
87 | /** | ||
88 | * How far are we? | ||
89 | */ | ||
90 | uint64_t publish_offset; | ||
91 | |||
92 | /** | ||
93 | * How deep are we? | ||
94 | */ | ||
95 | unsigned int current_depth; | ||
96 | |||
97 | /** | ||
98 | * How deep is the tree? | ||
99 | */ | ||
100 | unsigned int chk_tree_depth; | ||
101 | |||
102 | /** | ||
103 | * In-memory cache of the current CHK tree. | ||
104 | * This struct will contain the CHK values | ||
105 | * from the root to the currently processed | ||
106 | * node in the tree as identified by | ||
107 | * "current_depth" and "publish_offset". | ||
108 | * The "chktree" will be initially NULL, | ||
109 | * then allocated to a sufficient number of | ||
110 | * entries for the size of the file and | ||
111 | * finally freed once the upload is complete. | ||
112 | */ | ||
113 | struct ContentHashKey *chk_tree; | ||
114 | |||
115 | }; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Compute the depth of the CHK tree. | ||
120 | * | ||
121 | * @param flen file length for which to compute the depth | ||
122 | * @return depth of the tree | ||
123 | */ | ||
124 | static unsigned int | ||
125 | compute_depth (uint64_t flen) | ||
126 | { | ||
127 | unsigned int treeDepth; | ||
128 | uint64_t fl; | ||
129 | |||
130 | treeDepth = 1; | ||
131 | fl = DBLOCK_SIZE; | ||
132 | while (fl < flen) | ||
133 | { | ||
134 | treeDepth++; | ||
135 | if (fl * CHK_PER_INODE < fl) | ||
136 | { | ||
137 | /* integer overflow, this is a HUGE file... */ | ||
138 | return treeDepth; | ||
139 | } | ||
140 | fl = fl * CHK_PER_INODE; | ||
141 | } | ||
142 | return treeDepth; | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Initialize a tree encoder. This function will call "proc" and | ||
148 | * "progress" on each block in the tree. Once all blocks have been | ||
149 | * processed, "cont" will be scheduled. The "reader" will be called | ||
150 | * to obtain the (plaintext) blocks for the file. Note that this | ||
151 | * function will not actually call "proc". The client must | ||
152 | * call "GNUNET_FS_tree_encoder_next" to trigger encryption (and | ||
153 | * calling of "proc") for the each block. | ||
154 | * | ||
155 | * @param h the global FS context | ||
156 | * @param size overall size of the file to encode | ||
157 | * @param cls closure for reader, proc, progress and cont | ||
158 | * @param reader function to call to read plaintext data | ||
159 | * @param proc function to call on each encrypted block | ||
160 | * @param progress function to call with progress information | ||
161 | * @param cont function to call when done | ||
162 | */ | ||
163 | struct GNUNET_FS_TreeEncoder * | ||
164 | GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, | ||
165 | uint64_t size, | ||
166 | void *cls, | ||
167 | GNUNET_FS_DataReader reader, | ||
168 | GNUNET_FS_TreeBlockProcessor proc, | ||
169 | GNUNET_FS_TreeProgressCallback progress, | ||
170 | GNUNET_SCHEDULER_Task cont) | ||
171 | { | ||
172 | struct GNUNET_FS_TreeEncoder *te; | ||
173 | |||
174 | te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder)); | ||
175 | te->h = h; | ||
176 | te->size = size; | ||
177 | te->cls = cls; | ||
178 | te->reader = reader; | ||
179 | te->proc = proc; | ||
180 | te->progress = progress; | ||
181 | te->cont = cont; | ||
182 | te->chk_tree_depth = compute_depth (size); | ||
183 | te->current_depth = te->chk_tree_depth; | ||
184 | te->chk_tree = GNUNET_malloc (te->chk_tree_depth * | ||
185 | CHK_PER_INODE * | ||
186 | sizeof (struct ContentHashKey)); | ||
187 | return te; | ||
188 | } | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Compute the size of the current IBlock. | ||
193 | * | ||
194 | * @param height height of the IBlock in the tree (aka overall | ||
195 | * number of tree levels minus depth); 0 == DBlock | ||
196 | * @param offset current offset in the overall file | ||
197 | * @return size of the corresponding IBlock | ||
198 | */ | ||
199 | static uint16_t | ||
200 | compute_iblock_size (unsigned int height, | ||
201 | uint64_t offset) | ||
202 | { | ||
203 | unsigned int ret; | ||
204 | unsigned int i; | ||
205 | uint64_t mod; | ||
206 | uint64_t bds; | ||
207 | |||
208 | GNUNET_assert (height > 0); | ||
209 | bds = DBLOCK_SIZE; /* number of bytes each CHK at level "i" | ||
210 | corresponds to */ | ||
211 | for (i=0;i<height;i++) | ||
212 | bds *= CHK_PER_INODE; | ||
213 | mod = offset % bds; | ||
214 | if (0 == mod) | ||
215 | { | ||
216 | /* we were triggered at the end of a full block */ | ||
217 | ret = CHK_PER_INODE; | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | /* we were triggered at the end of the file */ | ||
222 | bds /= CHK_PER_INODE; | ||
223 | ret = mod / bds; | ||
224 | if (0 != mod % bds) | ||
225 | ret++; | ||
226 | } | ||
227 | return (uint16_t) (ret * sizeof(struct ContentHashKey)); | ||
228 | } | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Compute the offset of the CHK for the | ||
233 | * current block in the IBlock above. | ||
234 | * | ||
235 | * @param height height of the IBlock in the tree (aka overall | ||
236 | * number of tree levels minus depth); 0 == DBlock | ||
237 | * @param offset current offset in the overall file | ||
238 | * @return (array of CHKs') offset in the above IBlock | ||
239 | */ | ||
240 | static unsigned int | ||
241 | compute_chk_offset (unsigned int height, | ||
242 | uint64_t offset) | ||
243 | { | ||
244 | uint64_t bds; | ||
245 | unsigned int ret; | ||
246 | unsigned int i; | ||
247 | |||
248 | bds = DBLOCK_SIZE; /* number of bytes each CHK at level "i" | ||
249 | corresponds to */ | ||
250 | for (i=0;i<height;i++) | ||
251 | bds *= CHK_PER_INODE; | ||
252 | GNUNET_assert (0 == (offset % bds)); | ||
253 | ret = offset / bds; | ||
254 | return ret % CHK_PER_INODE; | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Encrypt the next block of the file (and | ||
260 | * call proc and progress accordingly; or | ||
261 | * of course "cont" if we have already completed | ||
262 | * encoding of the entire file). | ||
263 | * | ||
264 | * @param te tree encoder to use | ||
265 | */ | ||
266 | void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te) | ||
267 | { | ||
268 | struct ContentHashKey *mychk; | ||
269 | const void *pt_block; | ||
270 | uint16_t pt_size; | ||
271 | char iob[DBLOCK_SIZE]; | ||
272 | char enc[DBLOCK_SIZE]; | ||
273 | struct GNUNET_CRYPTO_AesSessionKey sk; | ||
274 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
275 | unsigned int off; | ||
276 | |||
277 | if (te->current_depth == te->chk_tree_depth) | ||
278 | { | ||
279 | pt_size = GNUNET_MIN(DBLOCK_SIZE, | ||
280 | te->size - te->publish_offset); | ||
281 | if (pt_size != | ||
282 | te->reader (te->cls, | ||
283 | te->publish_offset, | ||
284 | pt_size, | ||
285 | iob, | ||
286 | &te->emsg)) | ||
287 | { | ||
288 | GNUNET_SCHEDULER_add_continuation (te->h->sched, | ||
289 | GNUNET_NO, | ||
290 | te->cont, | ||
291 | te->cls, | ||
292 | GNUNET_SCHEDULER_REASON_TIMEOUT); | ||
293 | return; | ||
294 | } | ||
295 | pt_block = iob; | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | pt_size = compute_iblock_size (te->chk_tree_depth - te->current_depth, | ||
300 | te->publish_offset); | ||
301 | pt_block = &te->chk_tree[te->current_depth * | ||
302 | CHK_PER_INODE]; | ||
303 | } | ||
304 | off = compute_chk_offset (te->chk_tree_depth - te->current_depth, | ||
305 | te->publish_offset); | ||
306 | mychk = &te->chk_tree[(te->current_depth-1)*CHK_PER_INODE+off]; | ||
307 | GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key); | ||
308 | GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv); | ||
309 | GNUNET_CRYPTO_aes_encrypt (pt_block, | ||
310 | pt_size, | ||
311 | &sk, | ||
312 | &iv, | ||
313 | enc); | ||
314 | if (NULL != te->proc) | ||
315 | te->proc (te->cls, | ||
316 | &mychk->query, | ||
317 | te->publish_offset, | ||
318 | pt_size, | ||
319 | enc, | ||
320 | (te->current_depth == te->chk_tree_depth) | ||
321 | ? GNUNET_DATASTORE_BLOCKTYPE_DBLOCK | ||
322 | : GNUNET_DATASTORE_BLOCKTYPE_IBLOCK); | ||
323 | if (NULL != te->progress) | ||
324 | te->progress (te->cls, | ||
325 | te->publish_offset, | ||
326 | pt_block, | ||
327 | pt_size, | ||
328 | te->current_depth); | ||
329 | GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query); | ||
330 | if (te->current_depth == te->chk_tree_depth) | ||
331 | { | ||
332 | te->publish_offset += pt_size; | ||
333 | if ( (te->publish_offset == te->size) || | ||
334 | (0 == te->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE) ) ) | ||
335 | te->current_depth--; | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | if ( (off == CHK_PER_INODE) || | ||
340 | (te->publish_offset == te->size) ) | ||
341 | te->current_depth--; | ||
342 | else | ||
343 | te->current_depth = te->chk_tree_depth; | ||
344 | } | ||
345 | if (0 == te->current_depth) | ||
346 | { | ||
347 | te->uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri)); | ||
348 | te->uri->type = chk; | ||
349 | te->uri->data.chk.chk = te->chk_tree[0]; | ||
350 | te->uri->data.chk.file_length = te->size; | ||
351 | GNUNET_SCHEDULER_add_continuation (te->h->sched, | ||
352 | GNUNET_NO, | ||
353 | te->cont, | ||
354 | te->cls, | ||
355 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Clean up a tree encoder and return information | ||
362 | * about the resulting URI or an error message. | ||
363 | * | ||
364 | * @param te the tree encoder to clean up | ||
365 | * @param uri set to the resulting URI (if encoding finished) | ||
366 | * @param emsg set to an error message (if an error occured | ||
367 | * within the tree encoder; if this function is called | ||
368 | * prior to completion and prior to an internal error, | ||
369 | * both "*uri" and "*emsg" will be set to NULL). | ||
370 | */ | ||
371 | void GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder * te, | ||
372 | struct GNUNET_FS_Uri **uri, | ||
373 | char **emsg) | ||
374 | { | ||
375 | *uri = te->uri; | ||
376 | *emsg = te->emsg; | ||
377 | GNUNET_free (te->chk_tree); | ||
378 | GNUNET_free (te); | ||
379 | } | ||
380 | |||
381 | /* end of fs_tree.c */ | ||
diff --git a/src/fs/fs_tree.h b/src/fs/fs_tree.h new file mode 100644 index 000000000..f24130a3c --- /dev/null +++ b/src/fs/fs_tree.h | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_tree.h | ||
23 | * @brief Merkle-tree-ish-CHK file encoding for GNUnet | ||
24 | * @see http://gnunet.org/encoding.php3 | ||
25 | * @author Krista Bennett | ||
26 | * @author Christian Grothoff | ||
27 | * | ||
28 | * TODO: | ||
29 | * - decide if this API should be made public (gnunet_fs_service.h) | ||
30 | * or remain "internal" (but with exported symbols?) | ||
31 | */ | ||
32 | #ifndef GNUNET_FS_TREE_H | ||
33 | #define GNUNET_FS_TREE_H | ||
34 | |||
35 | #include "fs.h" | ||
36 | |||
37 | /** | ||
38 | * Context for an ECRS-based file encoder that computes | ||
39 | * the Merkle-ish-CHK tree. | ||
40 | */ | ||
41 | struct GNUNET_FS_TreeEncoder; | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Function called asking for the current (encoded) | ||
46 | * block to be processed. After processing the | ||
47 | * client should either call "GNUNET_FS_tree_encode_next" | ||
48 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
49 | * | ||
50 | * @param cls closure | ||
51 | * @param query the query for the block (key for lookup in the datastore) | ||
52 | * @param offset offset of the block | ||
53 | * @param type type of the block (IBLOCK or DBLOCK) | ||
54 | * @param block the (encrypted) block | ||
55 | * @param block_size size of block (in bytes) | ||
56 | */ | ||
57 | typedef void (*GNUNET_FS_TreeBlockProcessor)(void *cls, | ||
58 | const GNUNET_HashCode *query, | ||
59 | uint64_t offset, | ||
60 | unsigned int type, | ||
61 | const void *block, | ||
62 | uint16_t block_size); | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Function called with information about our | ||
67 | * progress in computing the tree encoding. | ||
68 | * | ||
69 | * @param cls closure | ||
70 | * @param offset where are we in the file | ||
71 | * @param pt_block plaintext of the currently processed block | ||
72 | * @param pt_size size of pt_block | ||
73 | * @param depth depth of the block in the tree | ||
74 | */ | ||
75 | typedef void (*GNUNET_FS_TreeProgressCallback)(void *cls, | ||
76 | uint64_t offset, | ||
77 | const void *pt_block, | ||
78 | size_t pt_size, | ||
79 | unsigned int depth); | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Initialize a tree encoder. This function will call "proc" and | ||
84 | * "progress" on each block in the tree. Once all blocks have been | ||
85 | * processed, "cont" will be scheduled. The "reader" will be called | ||
86 | * to obtain the (plaintext) blocks for the file. Note that this | ||
87 | * function will actually never call "proc"; the "proc" function must | ||
88 | * be triggered by calling "GNUNET_FS_tree_encoder_next" to trigger | ||
89 | * encryption (and calling of "proc") for each block. | ||
90 | * | ||
91 | * @param h the global FS context | ||
92 | * @param size overall size of the file to encode | ||
93 | * @param cls closure for reader, proc, progress and cont | ||
94 | * @param reader function to call to read plaintext data | ||
95 | * @param proc function to call on each encrypted block | ||
96 | * @param progress function to call with progress information | ||
97 | * @param cont function to call when done | ||
98 | */ | ||
99 | struct GNUNET_FS_TreeEncoder * | ||
100 | GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, | ||
101 | uint64_t size, | ||
102 | void *cls, | ||
103 | GNUNET_FS_DataReader reader, | ||
104 | GNUNET_FS_TreeBlockProcessor proc, | ||
105 | GNUNET_FS_TreeProgressCallback progress, | ||
106 | GNUNET_SCHEDULER_Task cont); | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Encrypt the next block of the file (and | ||
111 | * call proc and progress accordingly; or | ||
112 | * of course "cont" if we have already completed | ||
113 | * encoding of the entire file). | ||
114 | * | ||
115 | * @param te tree encoder to use | ||
116 | */ | ||
117 | void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder * te); | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Clean up a tree encoder and return information | ||
122 | * about the resulting URI or an error message. | ||
123 | * | ||
124 | * @param te the tree encoder to clean up | ||
125 | * @param uri set to the resulting URI (if encoding finished) | ||
126 | * @param emsg set to an error message (if an error occured | ||
127 | * within the tree encoder; if this function is called | ||
128 | * prior to completion and prior to an internal error, | ||
129 | * both "*uri" and "*emsg" will be set to NULL). | ||
130 | */ | ||
131 | void GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder * te, | ||
132 | struct GNUNET_FS_Uri **uri, | ||
133 | char **emsg); | ||
134 | |||
135 | |||
136 | #if 0 | ||
137 | /* the functions below will be needed for persistence | ||
138 | but are not yet implemented -- FIXME... */ | ||
139 | /** | ||
140 | * Get data that would be needed to resume | ||
141 | * the encoding later. | ||
142 | * | ||
143 | * @param te encoding to resume | ||
144 | * @param data set to the resume data | ||
145 | * @param size set to the size of the resume data | ||
146 | */ | ||
147 | void GNUNET_FS_tree_encoder_resume_get_data (const struct GNUNET_FS_TreeEncoder * te, | ||
148 | void **data, | ||
149 | size_t *size); | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Reset tree encoder to point previously | ||
154 | * obtained for resuming. | ||
155 | * | ||
156 | * @param te encoding to resume | ||
157 | * @param data the resume data | ||
158 | * @param size the size of the resume data | ||
159 | */ | ||
160 | void GNUNET_FS_tree_encoder_resume (struct GNUNET_FS_TreeEncoder * te, | ||
161 | const void *data, | ||
162 | size_t size); | ||
163 | #endif | ||
164 | |||
165 | #endif | ||
166 | |||
167 | /* end of fs_tree.h */ | ||