diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-04-26 15:25:27 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-04-26 15:25:27 +0000 |
commit | e6674963348824eb7d8bdfdc0e2d655ca9773a40 (patch) | |
tree | a46baf117e9b403de3ad618a3e5a85e2f616d278 /src/fs/fs_download.c | |
parent | 4868c316f36cbefb52e7823b7852a20373389a68 (diff) | |
download | gnunet-e6674963348824eb7d8bdfdc0e2d655ca9773a40.tar.gz gnunet-e6674963348824eb7d8bdfdc0e2d655ca9773a40.zip |
fully implement in-line files in directories
Diffstat (limited to 'src/fs/fs_download.c')
-rw-r--r-- | src/fs/fs_download.c | 294 |
1 files changed, 165 insertions, 129 deletions
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c index b179c70dc..8194ad9f5 100644 --- a/src/fs/fs_download.c +++ b/src/fs/fs_download.c | |||
@@ -532,11 +532,132 @@ trigger_recursive_download (void *cls, | |||
532 | const struct GNUNET_FS_Uri *uri, | 532 | const struct GNUNET_FS_Uri *uri, |
533 | const struct GNUNET_CONTAINER_MetaData *meta, | 533 | const struct GNUNET_CONTAINER_MetaData *meta, |
534 | size_t length, | 534 | size_t length, |
535 | const void *data); | ||
536 | |||
537 | |||
538 | /** | ||
539 | * We're done downloading a directory. Open the file and | ||
540 | * trigger all of the (remaining) child downloads. | ||
541 | * | ||
542 | * @param dc context of download that just completed | ||
543 | */ | ||
544 | static void | ||
545 | full_recursive_download (struct GNUNET_FS_DownloadContext *dc) | ||
546 | { | ||
547 | size_t size; | ||
548 | uint64_t size64; | ||
549 | void *data; | ||
550 | struct GNUNET_DISK_FileHandle *h; | ||
551 | struct GNUNET_DISK_MapHandle *m; | ||
552 | |||
553 | size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri); | ||
554 | size = (size_t) size64; | ||
555 | if (size64 != (uint64_t) size) | ||
556 | { | ||
557 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
558 | _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n")); | ||
559 | return; | ||
560 | } | ||
561 | if (dc->filename != NULL) | ||
562 | { | ||
563 | h = GNUNET_DISK_file_open (dc->filename, | ||
564 | GNUNET_DISK_OPEN_READ, | ||
565 | GNUNET_DISK_PERM_NONE); | ||
566 | } | ||
567 | else | ||
568 | { | ||
569 | GNUNET_assert (dc->temp_filename != NULL); | ||
570 | h = GNUNET_DISK_file_open (dc->temp_filename, | ||
571 | GNUNET_DISK_OPEN_READ, | ||
572 | GNUNET_DISK_PERM_NONE); | ||
573 | } | ||
574 | if (h == NULL) | ||
575 | return; /* oops */ | ||
576 | data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size); | ||
577 | if (data == NULL) | ||
578 | { | ||
579 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
580 | _("Directory too large for system address space\n")); | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | GNUNET_FS_directory_list_contents (size, | ||
585 | data, | ||
586 | 0, | ||
587 | &trigger_recursive_download, | ||
588 | dc); | ||
589 | GNUNET_DISK_file_unmap (m); | ||
590 | } | ||
591 | GNUNET_DISK_file_close (h); | ||
592 | if (dc->filename == NULL) | ||
593 | { | ||
594 | if (0 != UNLINK (dc->temp_filename)) | ||
595 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
596 | "unlink", | ||
597 | dc->temp_filename); | ||
598 | GNUNET_free (dc->temp_filename); | ||
599 | dc->temp_filename = NULL; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | |||
604 | /** | ||
605 | * Check if all child-downloads have completed and | ||
606 | * if so, signal completion (and possibly recurse to | ||
607 | * parent). | ||
608 | */ | ||
609 | static void | ||
610 | check_completed (struct GNUNET_FS_DownloadContext *dc) | ||
611 | { | ||
612 | struct GNUNET_FS_ProgressInfo pi; | ||
613 | struct GNUNET_FS_DownloadContext *pos; | ||
614 | |||
615 | pos = dc->child_head; | ||
616 | while (pos != NULL) | ||
617 | { | ||
618 | if ( (pos->emsg == NULL) && | ||
619 | (pos->completed < pos->length) ) | ||
620 | return; /* not done yet */ | ||
621 | if ( (pos->child_head != NULL) && | ||
622 | (pos->has_finished != GNUNET_YES) ) | ||
623 | return; /* not transitively done yet */ | ||
624 | pos = pos->next; | ||
625 | } | ||
626 | dc->has_finished = GNUNET_YES; | ||
627 | /* signal completion */ | ||
628 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED; | ||
629 | make_download_status (&pi, dc); | ||
630 | dc->client_info = dc->h->upcb (dc->h->upcb_cls, | ||
631 | &pi); | ||
632 | if (dc->parent != NULL) | ||
633 | check_completed (dc->parent); | ||
634 | } | ||
635 | |||
636 | |||
637 | /** | ||
638 | * We found an entry in a directory. Check if the respective child | ||
639 | * already exists and if not create the respective child download. | ||
640 | * | ||
641 | * @param cls the parent download | ||
642 | * @param filename name of the file in the directory | ||
643 | * @param uri URI of the file (CHK or LOC) | ||
644 | * @param meta meta data of the file | ||
645 | * @param length number of bytes in data | ||
646 | * @param data contents of the file (or NULL if they were not inlined) | ||
647 | */ | ||
648 | static void | ||
649 | trigger_recursive_download (void *cls, | ||
650 | const char *filename, | ||
651 | const struct GNUNET_FS_Uri *uri, | ||
652 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
653 | size_t length, | ||
535 | const void *data) | 654 | const void *data) |
536 | { | 655 | { |
537 | struct GNUNET_FS_DownloadContext *dc = cls; | 656 | struct GNUNET_FS_DownloadContext *dc = cls; |
538 | struct GNUNET_FS_DownloadContext *cpos; | 657 | struct GNUNET_FS_DownloadContext *cpos; |
539 | struct GNUNET_DISK_FileHandle *fh; | 658 | struct GNUNET_DISK_FileHandle *fh; |
659 | char *temp_name; | ||
660 | const char *real_name; | ||
540 | char *fn; | 661 | char *fn; |
541 | char *us; | 662 | char *us; |
542 | char *ext; | 663 | char *ext; |
@@ -632,45 +753,48 @@ trigger_recursive_download (void *cls, | |||
632 | GNUNET_free_non_null (fn); | 753 | GNUNET_free_non_null (fn); |
633 | return; | 754 | return; |
634 | } | 755 | } |
635 | 756 | ||
636 | if (data != NULL) | 757 | temp_name = NULL; |
758 | if ( (data != NULL) && | ||
759 | (GNUNET_FS_uri_chk_get_file_size (uri) == length) ) | ||
637 | { | 760 | { |
638 | if (full_name != NULL) | 761 | if (full_name == NULL) |
639 | { | 762 | { |
640 | fh = GNUNET_DISK_file_open (full_name, | 763 | temp_name = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); |
641 | GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, | 764 | real_name = temp_name; |
642 | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); | ||
643 | if (fh == NULL) | ||
644 | { | ||
645 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | ||
646 | "open", | ||
647 | full_name); | ||
648 | GNUNET_free (full_name); | ||
649 | GNUNET_free_non_null (fn); | ||
650 | return; | ||
651 | } | ||
652 | if (length != | ||
653 | GNUNET_DISK_file_write (fh, | ||
654 | data, | ||
655 | length)) | ||
656 | { | ||
657 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | ||
658 | "write", | ||
659 | full_name); | ||
660 | } | ||
661 | GNUNET_DISK_file_close (fh); | ||
662 | } | 765 | } |
663 | else | 766 | else |
664 | { | 767 | { |
665 | /* FIXME: generate 'progress' events and move to | 768 | real_name = full_name; |
666 | instant completion! */ | ||
667 | GNUNET_break (0); // FIXME: not implemented | ||
668 | } | 769 | } |
770 | /* write to disk, then trigger normal download which will instantly progress to completion */ | ||
771 | fh = GNUNET_DISK_file_open (real_name, | ||
772 | GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, | ||
773 | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); | ||
774 | if (fh == NULL) | ||
775 | { | ||
776 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | ||
777 | "open", | ||
778 | real_name); | ||
779 | GNUNET_free (full_name); | ||
780 | GNUNET_free_non_null (fn); | ||
781 | return; | ||
782 | } | ||
783 | if (length != | ||
784 | GNUNET_DISK_file_write (fh, | ||
785 | data, | ||
786 | length)) | ||
787 | { | ||
788 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | ||
789 | "write", | ||
790 | full_name); | ||
791 | } | ||
792 | GNUNET_DISK_file_close (fh); | ||
669 | } | 793 | } |
670 | GNUNET_FS_download_start (dc->h, | 794 | GNUNET_FS_download_start (dc->h, |
671 | uri, | 795 | uri, |
672 | meta, | 796 | meta, |
673 | full_name, | 797 | full_name, temp_name, |
674 | 0, | 798 | 0, |
675 | GNUNET_FS_uri_chk_get_file_size (uri), | 799 | GNUNET_FS_uri_chk_get_file_size (uri), |
676 | dc->anonymity, | 800 | dc->anonymity, |
@@ -678,110 +802,12 @@ trigger_recursive_download (void *cls, | |||
678 | NULL, | 802 | NULL, |
679 | dc); | 803 | dc); |
680 | GNUNET_free_non_null (full_name); | 804 | GNUNET_free_non_null (full_name); |
805 | GNUNET_free_non_null (temp_name); | ||
681 | GNUNET_free_non_null (fn); | 806 | GNUNET_free_non_null (fn); |
682 | } | 807 | } |
683 | 808 | ||
684 | 809 | ||
685 | /** | 810 | /** |
686 | * We're done downloading a directory. Open the file and | ||
687 | * trigger all of the (remaining) child downloads. | ||
688 | * | ||
689 | * @param dc context of download that just completed | ||
690 | */ | ||
691 | static void | ||
692 | full_recursive_download (struct GNUNET_FS_DownloadContext *dc) | ||
693 | { | ||
694 | size_t size; | ||
695 | uint64_t size64; | ||
696 | void *data; | ||
697 | struct GNUNET_DISK_FileHandle *h; | ||
698 | struct GNUNET_DISK_MapHandle *m; | ||
699 | |||
700 | size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri); | ||
701 | size = (size_t) size64; | ||
702 | if (size64 != (uint64_t) size) | ||
703 | { | ||
704 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
705 | _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n")); | ||
706 | return; | ||
707 | } | ||
708 | if (dc->filename != NULL) | ||
709 | { | ||
710 | h = GNUNET_DISK_file_open (dc->filename, | ||
711 | GNUNET_DISK_OPEN_READ, | ||
712 | GNUNET_DISK_PERM_NONE); | ||
713 | } | ||
714 | else | ||
715 | { | ||
716 | GNUNET_assert (dc->temp_filename != NULL); | ||
717 | h = GNUNET_DISK_file_open (dc->temp_filename, | ||
718 | GNUNET_DISK_OPEN_READ, | ||
719 | GNUNET_DISK_PERM_NONE); | ||
720 | } | ||
721 | if (h == NULL) | ||
722 | return; /* oops */ | ||
723 | data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size); | ||
724 | if (data == NULL) | ||
725 | { | ||
726 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
727 | _("Directory too large for system address space\n")); | ||
728 | } | ||
729 | else | ||
730 | { | ||
731 | GNUNET_FS_directory_list_contents (size, | ||
732 | data, | ||
733 | 0, | ||
734 | &trigger_recursive_download, | ||
735 | dc); | ||
736 | GNUNET_DISK_file_unmap (m); | ||
737 | } | ||
738 | GNUNET_DISK_file_close (h); | ||
739 | if (dc->filename == NULL) | ||
740 | { | ||
741 | if (0 != UNLINK (dc->temp_filename)) | ||
742 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
743 | "unlink", | ||
744 | dc->temp_filename); | ||
745 | GNUNET_free (dc->temp_filename); | ||
746 | dc->temp_filename = NULL; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | |||
751 | /** | ||
752 | * Check if all child-downloads have completed and | ||
753 | * if so, signal completion (and possibly recurse to | ||
754 | * parent). | ||
755 | */ | ||
756 | static void | ||
757 | check_completed (struct GNUNET_FS_DownloadContext *dc) | ||
758 | { | ||
759 | struct GNUNET_FS_ProgressInfo pi; | ||
760 | struct GNUNET_FS_DownloadContext *pos; | ||
761 | |||
762 | pos = dc->child_head; | ||
763 | while (pos != NULL) | ||
764 | { | ||
765 | if ( (pos->emsg == NULL) && | ||
766 | (pos->completed < pos->length) ) | ||
767 | return; /* not done yet */ | ||
768 | if ( (pos->child_head != NULL) && | ||
769 | (pos->has_finished != GNUNET_YES) ) | ||
770 | return; /* not transitively done yet */ | ||
771 | pos = pos->next; | ||
772 | } | ||
773 | dc->has_finished = GNUNET_YES; | ||
774 | /* signal completion */ | ||
775 | pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED; | ||
776 | make_download_status (&pi, dc); | ||
777 | dc->client_info = dc->h->upcb (dc->h->upcb_cls, | ||
778 | &pi); | ||
779 | if (dc->parent != NULL) | ||
780 | check_completed (dc->parent); | ||
781 | } | ||
782 | |||
783 | |||
784 | /** | ||
785 | * Iterator over entries in the pending requests in the 'active' map for the | 811 | * Iterator over entries in the pending requests in the 'active' map for the |
786 | * reply that we just got. | 812 | * reply that we just got. |
787 | * | 813 | * |
@@ -1264,6 +1290,10 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc) | |||
1264 | * @param meta known metadata for the file (can be NULL) | 1290 | * @param meta known metadata for the file (can be NULL) |
1265 | * @param filename where to store the file, maybe NULL (then no file is | 1291 | * @param filename where to store the file, maybe NULL (then no file is |
1266 | * created on disk and data must be grabbed from the callbacks) | 1292 | * created on disk and data must be grabbed from the callbacks) |
1293 | * @param tempname where to store temporary file data, not used if filename is non-NULL; | ||
1294 | * can be NULL (in which case we will pick a name if needed); the temporary file | ||
1295 | * may already exist, in which case we will try to use the data that is there and | ||
1296 | * if it is not what is desired, will overwrite it | ||
1267 | * @param offset at what offset should we start the download (typically 0) | 1297 | * @param offset at what offset should we start the download (typically 0) |
1268 | * @param length how many bytes should be downloaded starting at offset | 1298 | * @param length how many bytes should be downloaded starting at offset |
1269 | * @param anonymity anonymity level to use for the download | 1299 | * @param anonymity anonymity level to use for the download |
@@ -1278,6 +1308,7 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, | |||
1278 | const struct GNUNET_FS_Uri *uri, | 1308 | const struct GNUNET_FS_Uri *uri, |
1279 | const struct GNUNET_CONTAINER_MetaData *meta, | 1309 | const struct GNUNET_CONTAINER_MetaData *meta, |
1280 | const char *filename, | 1310 | const char *filename, |
1311 | const char *tempname, | ||
1281 | uint64_t offset, | 1312 | uint64_t offset, |
1282 | uint64_t length, | 1313 | uint64_t length, |
1283 | uint32_t anonymity, | 1314 | uint32_t anonymity, |
@@ -1352,7 +1383,12 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, | |||
1352 | dc->treedepth = GNUNET_FS_compute_depth (GNUNET_ntohll(dc->uri->data.chk.file_length)); | 1383 | dc->treedepth = GNUNET_FS_compute_depth (GNUNET_ntohll(dc->uri->data.chk.file_length)); |
1353 | if ( (filename == NULL) && | 1384 | if ( (filename == NULL) && |
1354 | (is_recursive_download (dc) ) ) | 1385 | (is_recursive_download (dc) ) ) |
1355 | dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); | 1386 | { |
1387 | if (tempname != NULL) | ||
1388 | dc->temp_filename = GNUNET_strdup (tempname); | ||
1389 | else | ||
1390 | dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); | ||
1391 | } | ||
1356 | 1392 | ||
1357 | #if DEBUG_DOWNLOAD | 1393 | #if DEBUG_DOWNLOAD |
1358 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1394 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |