2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file fs/fs_publish.c
23 * @brief publish a file or directory in GNUnet
24 * @see http://gnunet.org/encoding.php3
25 * @author Krista Bennett
26 * @author Christian Grothoff
29 * - code-sharing with unindex (write unindex code)
30 * - indexing cleanup: unindex on failure (can wait)
31 * - persistence support (can wait)
32 * - datastore reservation support (optimization)
33 * - location URIs (publish with anonymity-level zero)
37 #include "gnunet_constants.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_util_lib.h"
40 #include "gnunet_fs_service.h"
44 #define DEBUG_PUBLISH GNUNET_YES
47 * Maximum allowed size for a KBlock.
49 #define MAX_KBLOCK_SIZE 60000
52 * Maximum allowed size for an SBlock.
54 #define MAX_SBLOCK_SIZE 60000
57 * Main function that performs the upload.
58 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload
59 * @param tc task context
63 const struct GNUNET_SCHEDULER_TaskContext *tc);
67 * Context for "ds_put_cont".
72 * Current publishing context.
74 struct GNUNET_FS_PublishContext *sc;
77 * Specific file with the block.
79 struct GNUNET_FS_FileInformation *p;
82 * Function to run next, if any (can be NULL).
84 GNUNET_SCHEDULER_Task cont;
94 * Fill in all of the generic fields for
97 * @param pc structure to fill in
98 * @param sc overall publishing context
99 * @param p file information for the file being published
100 * @param offset where in the file are we so far
103 make_publish_status (struct GNUNET_FS_ProgressInfo *pi,
104 struct GNUNET_FS_PublishContext *sc,
105 const struct GNUNET_FS_FileInformation *p,
108 pi->value.publish.sc = sc;
109 pi->value.publish.fi = p;
110 pi->value.publish.cctx
112 pi->value.publish.pctx
113 = (NULL == p->dir) ? NULL : p->dir->client_info;
114 pi->value.publish.size
115 = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size;
116 pi->value.publish.eta
117 = GNUNET_TIME_calculate_eta (p->start_time,
119 pi->value.publish.size);
120 pi->value.publish.completed = offset;
121 pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (p->start_time);
122 pi->value.publish.anonymity = p->anonymity;
127 * Cleanup the publish context, we're done
130 * @param pc struct to clean up after
133 publish_cleanup (struct GNUNET_FS_PublishContext *sc)
135 GNUNET_FS_file_information_destroy (sc->fi, NULL, NULL);
136 GNUNET_FS_namespace_delete (sc->namespace, GNUNET_NO);
137 GNUNET_free_non_null (sc->nid);
138 GNUNET_free_non_null (sc->nuid);
139 GNUNET_DATASTORE_disconnect (sc->dsh, GNUNET_NO);
145 * Function called by the datastore API with
146 * the result from the PUT request.
148 * @param cls our closure
149 * @param success GNUNET_OK on success
150 * @param msg error message (or NULL)
153 ds_put_cont (void *cls,
157 struct PutContCtx *pcc = cls;
158 struct GNUNET_FS_ProgressInfo pi;
160 if (GNUNET_SYSERR == pcc->sc->in_network_wait)
162 /* we were aborted in the meantime,
164 publish_cleanup (pcc->sc);
167 GNUNET_assert (GNUNET_YES == pcc->sc->in_network_wait);
168 pcc->sc->in_network_wait = GNUNET_NO;
169 if (GNUNET_OK != success)
171 GNUNET_asprintf (&pcc->p->emsg,
172 _("Upload failed: %s"),
174 GNUNET_FS_file_information_sync (pcc->p);
175 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
176 make_publish_status (&pi, pcc->sc, pcc->p, 0);
177 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
178 pi.value.publish.specifics.error.message = pcc->p->emsg;
180 = pcc->sc->h->upcb (pcc->sc->h->upcb_cls,
184 GNUNET_FS_file_information_sync (pcc->p);
185 if (NULL != pcc->cont)
187 = GNUNET_SCHEDULER_add_delayed (pcc->sc->h->sched,
189 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
190 GNUNET_SCHEDULER_NO_TASK,
191 GNUNET_TIME_UNIT_ZERO,
199 * Generate the callback that signals clients
200 * that a file (or directory) has been completely
203 * @param p the completed upload
204 * @param sc context of the publication
207 signal_publish_completion (struct GNUNET_FS_FileInformation *p,
208 struct GNUNET_FS_PublishContext *sc)
210 struct GNUNET_FS_ProgressInfo pi;
212 pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED;
213 make_publish_status (&pi, sc, p,
214 GNUNET_ntohll (p->chk_uri->data.chk.file_length));
215 pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO;
216 pi.value.publish.specifics.completed.chk_uri = p->chk_uri;
218 = sc->h->upcb (sc->h->upcb_cls,
224 * Generate the callback that signals clients
225 * that a file (or directory) has encountered
226 * a problem during publication.
228 * @param p the upload that had trouble
229 * @param sc context of the publication
230 * @param emsg error message
233 signal_publish_error (struct GNUNET_FS_FileInformation *p,
234 struct GNUNET_FS_PublishContext *sc,
237 struct GNUNET_FS_ProgressInfo pi;
239 p->emsg = GNUNET_strdup (emsg);
240 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
241 make_publish_status (&pi, sc, p, 0);
242 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
243 pi.value.publish.specifics.error.message =emsg;
245 = sc->h->upcb (sc->h->upcb_cls,
251 * We've finished publishing the SBlock as part of a larger upload.
252 * Check the result and complete the larger upload.
254 * @param cls the "struct GNUNET_FS_PublishContext*" of the larger upload
255 * @param uri URI of the published SBlock
256 * @param emsg NULL on success, otherwise error message
259 publish_sblocks_cont (void *cls,
260 const struct GNUNET_FS_Uri *uri,
263 struct GNUNET_FS_PublishContext *sc = cls;
266 signal_publish_error (sc->fi,
271 // FIXME: release the datastore reserve here!
272 signal_publish_completion (sc->fi, sc);
277 * We are almost done publishing the structure,
278 * add SBlocks (if needed).
280 * @param sc overall upload data
283 publish_sblock (struct GNUNET_FS_PublishContext *sc)
285 if (NULL != sc->namespace)
286 GNUNET_FS_publish_sks (sc->h,
292 sc->fi->expirationTime,
296 &publish_sblocks_cont,
299 publish_sblocks_cont (sc, NULL, NULL);
304 * We've finished publishing a KBlock
305 * as part of a larger upload. Check
306 * the result and continue the larger
309 * @param cls the "struct GNUNET_FS_PublishContext*"
310 * of the larger upload
311 * @param uri URI of the published blocks
312 * @param emsg NULL on success, otherwise error message
315 publish_kblocks_cont (void *cls,
316 const struct GNUNET_FS_Uri *uri,
319 struct GNUNET_FS_PublishContext *sc = cls;
320 struct GNUNET_FS_FileInformation *p = sc->fi_pos;
324 signal_publish_error (p, sc, emsg);
326 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
328 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
329 GNUNET_SCHEDULER_NO_TASK,
330 GNUNET_TIME_UNIT_ZERO,
335 GNUNET_FS_file_information_sync (p);
337 signal_publish_completion (p, sc);
338 /* move on to next file */
340 sc->fi_pos = p->next;
344 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
346 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
347 GNUNET_SCHEDULER_NO_TASK,
348 GNUNET_TIME_UNIT_ZERO,
355 * Function called by the tree encoder to obtain
356 * a block of plaintext data (for the lowest level
359 * @param cls our publishing context
360 * @param offset identifies which block to get
361 * @param max (maximum) number of bytes to get; returning
362 * fewer will also cause errors
363 * @param buf where to copy the plaintext buffer
364 * @param emsg location to store an error message (on error)
365 * @return number of bytes copied to buf, 0 on error
368 block_reader (void *cls,
374 struct GNUNET_FS_PublishContext *sc = cls;
375 struct GNUNET_FS_FileInformation *p;
382 pt_size = GNUNET_MIN(max,
383 p->data.dir.dir_size - offset);
384 dd = p->data.dir.dir_data;
391 pt_size = GNUNET_MIN(max,
392 p->data.file.file_size - offset);
394 p->data.file.reader (p->data.file.reader_cls,
406 * The tree encoder has finished processing a
407 * file. Call it's finish method and deal with
410 * @param cls our publishing context
411 * @param tc scheduler's task context (not used)
414 encode_cont (void *cls,
415 const struct GNUNET_SCHEDULER_TaskContext *tc)
417 struct GNUNET_FS_PublishContext *sc = cls;
418 struct GNUNET_FS_FileInformation *p;
419 struct GNUNET_FS_ProgressInfo pi;
423 GNUNET_FS_tree_encoder_finish (p->te,
429 GNUNET_asprintf (&p->emsg,
430 _("Upload failed: %s"),
433 GNUNET_FS_file_information_sync (p);
434 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
435 make_publish_status (&pi, sc, p, 0);
436 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
437 pi.value.publish.specifics.error.message = p->emsg;
439 = sc->h->upcb (sc->h->upcb_cls,
442 /* continue with main */
444 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
446 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
447 GNUNET_SCHEDULER_NO_TASK,
448 GNUNET_TIME_UNIT_ZERO,
455 * Function called asking for the current (encoded)
456 * block to be processed. After processing the
457 * client should either call "GNUNET_FS_tree_encode_next"
458 * or (on error) "GNUNET_FS_tree_encode_finish".
461 * @param query the query for the block (key for lookup in the datastore)
462 * @param type type of the block (IBLOCK or DBLOCK)
463 * @param block the (encrypted) block
464 * @param block_size size of block (in bytes)
467 block_proc (void *cls,
468 const GNUNET_HashCode *query,
474 struct GNUNET_FS_PublishContext *sc = cls;
475 struct GNUNET_FS_FileInformation *p;
476 struct PutContCtx * dpc_cls;
477 struct OnDemandBlock odb;
483 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
485 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
486 GNUNET_SCHEDULER_NO_TASK,
487 GNUNET_TIME_UNIT_ZERO,
493 GNUNET_assert (GNUNET_NO == sc->in_network_wait);
494 sc->in_network_wait = GNUNET_YES;
495 dpc_cls = GNUNET_malloc(sizeof(struct PutContCtx));
496 dpc_cls->cont = &do_upload;
497 dpc_cls->cont_cls = sc;
499 if ( (p->is_directory) &&
500 (p->data.file.do_index) &&
501 (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) )
504 odb.file_id = p->data.file.file_id;
505 GNUNET_DATASTORE_put (sc->dsh,
508 sizeof(struct OnDemandBlock),
510 GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND,
514 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
519 GNUNET_DATASTORE_put (sc->dsh,
528 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
535 * Function called with information about our
536 * progress in computing the tree encoding.
539 * @param offset where are we in the file
540 * @param pt_block plaintext of the currently processed block
541 * @param pt_size size of pt_block
542 * @param depth depth of the block in the tree
545 progress_proc (void *cls,
547 const void *pt_block,
551 struct GNUNET_FS_PublishContext *sc = cls;
552 struct GNUNET_FS_FileInformation *p;
553 struct GNUNET_FS_ProgressInfo pi;
556 pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS;
557 make_publish_status (&pi, sc, p, offset);
558 pi.value.publish.specifics.progress.data = pt_block;
559 pi.value.publish.specifics.progress.offset = offset;
560 pi.value.publish.specifics.progress.data_len = pt_size;
561 pi.value.publish.specifics.progress.depth = depth;
563 = sc->h->upcb (sc->h->upcb_cls,
569 * We are uploading a file or directory; load (if necessary) the next
570 * block into memory, encrypt it and send it to the FS service. Then
571 * continue with the main task.
573 * @param sc overall upload data
576 publish_content (struct GNUNET_FS_PublishContext *sc)
578 struct GNUNET_FS_FileInformation *p;
580 struct GNUNET_FS_DirectoryBuilder *db;
581 struct GNUNET_FS_FileInformation *dirpos;
590 db = GNUNET_FS_directory_builder_create (p->meta);
591 dirpos = p->data.dir.entries;
592 while (NULL != dirpos)
594 if (dirpos->is_directory)
596 raw_data = dirpos->data.dir.dir_data;
597 dirpos->data.dir.dir_data = NULL;
602 if ( (dirpos->data.file.file_size < MAX_INLINE_SIZE) &&
603 (dirpos->data.file.file_size > 0) )
605 raw_data = GNUNET_malloc (dirpos->data.file.file_size);
607 if (dirpos->data.file.file_size !=
608 dirpos->data.file.reader (dirpos->data.file.reader_cls,
610 dirpos->data.file.file_size,
614 GNUNET_free_non_null (emsg);
615 GNUNET_free (raw_data);
620 GNUNET_FS_directory_builder_add (db,
624 GNUNET_free_non_null (raw_data);
625 dirpos = dirpos->next;
627 GNUNET_FS_directory_builder_finish (db,
628 &p->data.dir.dir_size,
629 &p->data.dir.dir_data);
631 size = (p->is_directory)
632 ? p->data.dir.dir_size
633 : p->data.file.file_size;
634 p->te = GNUNET_FS_tree_encoder_create (sc->h,
643 GNUNET_FS_tree_encoder_next (p->te);
648 * Process the response (or lack thereof) from
649 * the "fs" service to our 'start index' request.
651 * @param cls closure (of type "struct GNUNET_FS_PublishContext*"_)
652 * @param msg the response we got
655 process_index_start_response (void *cls,
656 const struct GNUNET_MessageHeader *msg)
658 struct GNUNET_FS_PublishContext *sc = cls;
659 struct GNUNET_FS_FileInformation *p;
663 GNUNET_CLIENT_disconnect (sc->client);
668 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
669 _("Can not index file `%s': %s. Will try to insert instead.\n"),
670 p->data.file.filename,
671 _("timeout on index-start request to `fs' service"));
672 p->data.file.do_index = GNUNET_NO;
673 publish_content (sc);
676 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK)
678 msize = ntohs (msg->size);
679 emsg = (const char *) &msg[1];
680 if ( (msize <= sizeof (struct GNUNET_MessageHeader)) ||
681 (emsg[msize - sizeof(struct GNUNET_MessageHeader) - 1] != '\0') )
682 emsg = gettext_noop ("unknown error");
683 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
684 _("Can not index file `%s': %s. Will try to insert instead.\n"),
685 p->data.file.filename,
687 p->data.file.do_index = GNUNET_NO;
688 publish_content (sc);
691 /* success! continue with indexing */
692 publish_content (sc);
697 #include <sys/statvfs.h>
701 * Function called once the hash computation over an
702 * indexed file has completed.
704 * @param cls closure, our publishing context
705 * @param res resulting hash, NULL on error
708 hash_for_index_cb (void *cls,
709 const GNUNET_HashCode *
712 struct GNUNET_FS_PublishContext *sc = cls;
713 struct GNUNET_FS_FileInformation *p;
714 struct IndexStartMessage *ism;
716 struct GNUNET_CLIENT_Connection *client;
725 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
726 _("Can not index file `%s': %s. Will try to insert instead.\n"),
727 p->data.file.filename,
728 _("failed to compute hash"));
729 p->data.file.do_index = GNUNET_NO;
730 publish_content (sc);
733 slen = strlen (p->data.file.filename) + 1;
734 if (slen > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof(struct IndexStartMessage))
736 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
737 _("Can not index file `%s': %s. Will try to insert instead.\n"),
738 p->data.file.filename,
739 _("filename too long"));
740 p->data.file.do_index = GNUNET_NO;
741 publish_content (sc);
744 client = GNUNET_CLIENT_connect (sc->h->sched,
749 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
750 _("Can not index file `%s': %s. Will try to insert instead.\n"),
751 p->data.file.filename,
752 _("could not connect to `fs' service"));
753 p->data.file.do_index = GNUNET_NO;
754 publish_content (sc);
757 p->data.file.file_id = *res;
758 ism = GNUNET_malloc (sizeof(struct IndexStartMessage) +
760 ism->header.size = htons(sizeof(struct IndexStartMessage) +
762 ism->header.type = htons(GNUNET_MESSAGE_TYPE_FS_INDEX_START);
763 /* FIXME: activate this on other OSes that
764 support it (or something very similar; make
765 sure to also adjust corresponding code
766 on the service-side) */
767 /* FIXME: the block below should probably be
768 abstracted into a function in the DISK API */
770 if ( (0 == stat(p->data.file.filename,
772 (0 == statvfs (p->data.file.filename,
775 ism->device = htonl ((uint32_t) fbuf.f_fsid);
776 ism->inode = GNUNET_htonll( (uint64_t) sbuf.st_ino);
780 p->data.file.filename,
783 GNUNET_CLIENT_transmit_and_get_response (client,
785 GNUNET_TIME_UNIT_FOREVER_REL,
786 &process_index_start_response,
793 * Main function that performs the upload.
794 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload
795 * @param tc task context
798 do_upload (void *cls,
799 const struct GNUNET_SCHEDULER_TaskContext *tc)
801 struct GNUNET_FS_PublishContext *sc = cls;
802 struct GNUNET_FS_ProgressInfo pi;
803 struct GNUNET_FS_FileInformation *p;
806 sc->upload_task = GNUNET_SCHEDULER_NO_TASK;
810 /* upload of entire hierarchy complete,
811 publish namespace entries */
815 /* find starting position */
816 while ( (p->is_directory) &&
817 (NULL != p->data.dir.entries) &&
819 (NULL == p->data.dir.entries->chk_uri) )
821 p = p->data.dir.entries;
827 /* error with current file, abort all
828 related files as well! */
829 while (NULL != p->dir)
831 fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta,
834 GNUNET_asprintf (&p->emsg,
835 _("Recursive upload failed at `%s'"),
838 GNUNET_FS_file_information_sync (p);
839 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
840 make_publish_status (&pi, sc, p, 0);
841 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
842 pi.value.publish.specifics.error.message = p->emsg;
844 = sc->h->upcb (sc->h->upcb_cls,
849 /* handle completion */
850 if (NULL != p->chk_uri)
852 /* upload of "p" complete, publish KBlocks! */
853 GNUNET_FS_publish_ksk (sc->h,
861 &publish_kblocks_cont,
865 if ( (!p->is_directory) &&
866 (p->data.file.do_index) )
868 if (NULL == p->data.file.filename)
870 p->data.file.do_index = GNUNET_NO;
871 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
872 _("Can not index file `%s': %s. Will try to insert instead.\n"),
874 _("needs to be an actual file"));
875 publish_content (sc);
878 GNUNET_CRYPTO_hash_file (sc->h->sched,
879 GNUNET_SCHEDULER_PRIORITY_IDLE,
881 p->data.file.filename,
887 publish_content (sc);
892 * Signal the FS's progress function that we are starting
895 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
896 * @param fi the entry in the publish-structure
897 * @param length length of the file or directory
898 * @param meta metadata for the file or directory (can be modified)
899 * @param uri pointer to the keywords that will be used for this entry (can be modified)
900 * @param anonymity pointer to selected anonymity level (can be modified)
901 * @param priority pointer to selected priority (can be modified)
902 * @param expirationTime pointer to selected expiration time (can be modified)
903 * @param client_info pointer to client context set upon creation (can be modified)
904 * @return GNUNET_OK to continue (always)
907 fip_signal_start(void *cls,
908 struct GNUNET_FS_FileInformation *fi,
910 struct GNUNET_CONTAINER_MetaData *meta,
911 struct GNUNET_FS_Uri **uri,
912 unsigned int *anonymity,
913 unsigned int *priority,
914 struct GNUNET_TIME_Absolute *expirationTime,
917 struct GNUNET_FS_PublishContext *sc = cls;
918 struct GNUNET_FS_ProgressInfo pi;
920 pi.status = GNUNET_FS_STATUS_PUBLISH_START;
921 make_publish_status (&pi, sc, fi, 0);
922 *client_info = sc->h->upcb (sc->h->upcb_cls,
929 * Publish a file or directory.
931 * @param h handle to the file sharing subsystem
932 * @param ctx initial value to use for the '*ctx'
933 * in the callback (for the GNUNET_FS_STATUS_PUBLISH_START event).
934 * @param fi information about the file or directory structure to publish
935 * @param namespace namespace to publish the file in, NULL for no namespace
936 * @param nid identifier to use for the publishd content in the namespace
937 * (can be NULL, must be NULL if namespace is NULL)
938 * @param nuid update-identifier that will be used for future updates
939 * (can be NULL, must be NULL if namespace or nid is NULL)
940 * @param options options for the publication
941 * @return context that can be used to control the publish operation
943 struct GNUNET_FS_PublishContext *
944 GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h,
946 struct GNUNET_FS_FileInformation *fi,
947 struct GNUNET_FS_Namespace *namespace,
950 enum GNUNET_FS_PublishOptions options)
952 struct GNUNET_FS_PublishContext *ret;
953 struct GNUNET_DATASTORE_Handle *dsh;
955 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
957 dsh = GNUNET_DATASTORE_connect (h->cfg,
966 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext));
969 ret->client_ctx = ctx;
971 ret->namespace = namespace;
972 if (namespace != NULL)
975 GNUNET_assert (NULL != nid);
976 ret->nid = GNUNET_strdup (nid);
978 ret->nuid = GNUNET_strdup (nuid);
980 // FIXME: make upload persistent!
983 GNUNET_FS_file_information_inspect (ret->fi,
986 ret->fi_pos = ret->fi;
988 // FIXME: calculate space needed for "fi"
989 // and reserve as first task (then trigger
990 // "do_upload" from that continuation)!
992 = GNUNET_SCHEDULER_add_delayed (h->sched,
994 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
995 GNUNET_SCHEDULER_NO_TASK,
996 GNUNET_TIME_UNIT_ZERO,
1004 * Signal the FS's progress function that we are stopping
1007 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
1008 * @param fi the entry in the publish-structure
1009 * @param length length of the file or directory
1010 * @param meta metadata for the file or directory (can be modified)
1011 * @param uri pointer to the keywords that will be used for this entry (can be modified)
1012 * @param anonymity pointer to selected anonymity level (can be modified)
1013 * @param priority pointer to selected priority (can be modified)
1014 * @param expirationTime pointer to selected expiration time (can be modified)
1015 * @param client_info pointer to client context set upon creation (can be modified)
1016 * @return GNUNET_OK to continue (always)
1019 fip_signal_stop(void *cls,
1020 struct GNUNET_FS_FileInformation *fi,
1022 struct GNUNET_CONTAINER_MetaData *meta,
1023 struct GNUNET_FS_Uri **uri,
1024 unsigned int *anonymity,
1025 unsigned int *priority,
1026 struct GNUNET_TIME_Absolute *expirationTime,
1029 struct GNUNET_FS_PublishContext*sc = cls;
1030 struct GNUNET_FS_ProgressInfo pi;
1033 off = (fi->chk_uri == NULL) ? 0 : length;
1034 pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED;
1035 make_publish_status (&pi, sc, fi, off);
1036 GNUNET_break (NULL ==
1037 sc->h->upcb (sc->h->upcb_cls,
1039 *client_info = NULL;
1045 * Stop an upload. Will abort incomplete uploads (but
1046 * not remove blocks that have already been publishd) or
1047 * simply clean up the state for completed uploads.
1049 * @param sc context for the upload to stop
1052 GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *sc)
1054 if (GNUNET_SCHEDULER_NO_TASK != sc->upload_task)
1055 GNUNET_SCHEDULER_cancel (sc->h->sched, sc->upload_task);
1056 // FIXME: remove from persistence DB (?) --- think more about
1057 // shutdown / persistent-resume APIs!!!
1058 GNUNET_FS_file_information_inspect (sc->fi,
1061 if (GNUNET_YES == sc->in_network_wait)
1063 sc->in_network_wait = GNUNET_SYSERR;
1066 publish_cleanup (sc);
1071 * Context for the KSK publication.
1073 struct PublishKskContext
1079 struct GNUNET_FS_Uri *ksk_uri;
1082 * Global FS context.
1084 struct GNUNET_FS_Handle *h;
1087 * The master block that we are sending
1088 * (in plaintext), has "mdsize+slen" more
1089 * bytes than the struct would suggest.
1094 * Buffer of the same size as "kb" for
1095 * the encrypted version.
1100 * Handle to the datastore, NULL if we are just
1103 struct GNUNET_DATASTORE_Handle *dsh;
1106 * Function to call once we're done.
1108 GNUNET_FS_PublishContinuation cont;
1116 * When should the KBlocks expire?
1118 struct GNUNET_TIME_Absolute expirationTime;
1121 * Size of the serialized metadata.
1126 * Size of the (CHK) URI as a string.
1131 * Keyword that we are currently processing.
1136 * Anonymity level for the KBlocks.
1138 unsigned int anonymity;
1141 * Priority for the KBlocks.
1143 unsigned int priority;
1148 * Continuation of "GNUNET_FS_publish_ksk" that performs
1149 * the actual publishing operation (iterating over all
1152 * @param cls closure of type "struct PublishKskContext*"
1156 publish_ksk_cont (void *cls,
1157 const struct GNUNET_SCHEDULER_TaskContext *tc);
1161 * Function called by the datastore API with
1162 * the result from the PUT request.
1164 * @param cls closure of type "struct PublishKskContext*"
1165 * @param success GNUNET_OK on success
1166 * @param msg error message (or NULL)
1169 kb_put_cont (void *cls,
1173 struct PublishKskContext *pkc = cls;
1175 if (GNUNET_OK != success)
1177 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1178 GNUNET_free (pkc->cpy);
1179 GNUNET_free (pkc->kb);
1180 pkc->cont (pkc->cont_cls,
1183 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1187 GNUNET_SCHEDULER_add_continuation (pkc->h->sched,
1191 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1196 * Continuation of "GNUNET_FS_publish_ksk" that performs
1197 * the actual publishing operation (iterating over all
1200 * @param cls closure of type "struct PublishKskContext*"
1204 publish_ksk_cont (void *cls,
1205 const struct GNUNET_SCHEDULER_TaskContext *tc)
1207 struct PublishKskContext *pkc = cls;
1208 const char *keyword;
1209 GNUNET_HashCode key;
1210 GNUNET_HashCode query;
1211 struct GNUNET_CRYPTO_AesSessionKey skey;
1212 struct GNUNET_CRYPTO_AesInitializationVector iv;
1213 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
1216 if ( (pkc->i == pkc->ksk_uri->data.ksk.keywordCount) ||
1217 (NULL == pkc->dsh) )
1219 if (NULL != pkc->dsh)
1220 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1221 GNUNET_free (pkc->cpy);
1222 GNUNET_free (pkc->kb);
1223 pkc->cont (pkc->cont_cls,
1226 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1230 keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
1231 /* first character of keyword indicates if it is
1232 mandatory or not -- ignore for hashing */
1233 GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
1234 GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
1235 GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1],
1236 pkc->slen + pkc->mdsize,
1240 pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
1241 GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace);
1242 GNUNET_CRYPTO_hash (&pkc->cpy->keyspace,
1243 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1245 GNUNET_assert (GNUNET_OK ==
1246 GNUNET_CRYPTO_rsa_sign (pk,
1248 &pkc->cpy->signature));
1249 GNUNET_CRYPTO_rsa_key_free (pk);
1250 GNUNET_DATASTORE_put (pkc->dsh,
1254 sizeof (struct KBlock) +
1257 GNUNET_DATASTORE_BLOCKTYPE_KBLOCK,
1260 pkc->expirationTime,
1261 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1268 * Publish a CHK under various keywords on GNUnet.
1270 * @param h handle to the file sharing subsystem
1271 * @param ksk_uri keywords to use
1272 * @param meta metadata to use
1273 * @param uri URI to refer to in the KBlock
1274 * @param expirationTime when the KBlock expires
1275 * @param anonymity anonymity level for the KBlock
1276 * @param priority priority for the KBlock
1277 * @param options publication options
1278 * @param cont continuation
1279 * @param cont_cls closure for cont
1282 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
1283 struct GNUNET_FS_Uri *ksk_uri,
1284 struct GNUNET_CONTAINER_MetaData *meta,
1285 struct GNUNET_FS_Uri *uri,
1286 struct GNUNET_TIME_Absolute expirationTime,
1287 unsigned int anonymity,
1288 unsigned int priority,
1289 enum GNUNET_FS_PublishOptions options,
1290 GNUNET_FS_PublishContinuation cont,
1293 struct PublishKskContext *pkc;
1298 pkc = GNUNET_malloc (sizeof (struct PublishKskContext));
1300 pkc->expirationTime = expirationTime;
1301 pkc->anonymity = anonymity;
1302 pkc->priority = priority;
1304 pkc->cont_cls = cont_cls;
1305 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1307 pkc->dsh = GNUNET_DATASTORE_connect (h->cfg,
1309 if (pkc->dsh == NULL)
1311 cont (cont_cls, NULL, _("Could not connect to datastore."));
1316 pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1317 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1318 GNUNET_assert (pkc->mdsize >= 0);
1319 uris = GNUNET_FS_uri_to_string (uri);
1320 pkc->slen = strlen (uris) + 1;
1321 size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen;
1322 if (size > MAX_KBLOCK_SIZE)
1324 size = MAX_KBLOCK_SIZE;
1325 pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen;
1327 pkc->kb = GNUNET_malloc (size);
1328 kbe = (char *) &pkc->kb[1];
1329 memcpy (kbe, uris, pkc->slen);
1331 pkc->mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1334 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1335 if (pkc->mdsize == -1)
1339 GNUNET_free (pkc->kb);
1340 if (pkc->dsh != NULL)
1341 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1342 cont (cont_cls, NULL, _("Internal error."));
1346 size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize;
1348 pkc->cpy = GNUNET_malloc (size);
1349 pkc->cpy->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
1350 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
1353 pkc->cpy->purpose.purpose = htonl(GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK);
1354 pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
1355 GNUNET_SCHEDULER_add_continuation (h->sched,
1359 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1364 * Context for the SKS publication.
1366 struct PublishSksContext
1370 * Global FS context.
1372 struct GNUNET_FS_Uri *uri;
1375 * Handle to the datastore.
1377 struct GNUNET_DATASTORE_Handle *dsh;
1380 * Function to call once we're done.
1382 GNUNET_FS_PublishContinuation cont;
1393 * Function called by the datastore API with
1394 * the result from the PUT (SBlock) request.
1396 * @param cls closure of type "struct PublishSksContext*"
1397 * @param success GNUNET_OK on success
1398 * @param msg error message (or NULL)
1401 sb_put_cont (void *cls,
1405 struct PublishSksContext *psc = cls;
1407 if (NULL != psc->dsh)
1408 GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
1409 if (GNUNET_OK != success)
1410 psc->cont (psc->cont_cls,
1414 psc->cont (psc->cont_cls,
1417 GNUNET_FS_uri_destroy (psc->uri);
1423 * Publish an SBlock on GNUnet.
1425 * @param h handle to the file sharing subsystem
1426 * @param namespace namespace to publish in
1427 * @param identifier identifier to use
1428 * @param update update identifier to use
1429 * @param meta metadata to use
1430 * @param uri URI to refer to in the SBlock
1431 * @param expirationTime when the SBlock expires
1432 * @param anonymity anonymity level for the SBlock
1433 * @param priority priority for the SBlock
1434 * @param options publication options
1435 * @param cont continuation
1436 * @param cont_cls closure for cont
1439 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
1440 struct GNUNET_FS_Namespace *namespace,
1441 const char *identifier,
1443 struct GNUNET_CONTAINER_MetaData *meta,
1444 struct GNUNET_FS_Uri *uri,
1445 struct GNUNET_TIME_Absolute expirationTime,
1446 unsigned int anonymity,
1447 unsigned int priority,
1448 enum GNUNET_FS_PublishOptions options,
1449 GNUNET_FS_PublishContinuation cont,
1452 struct PublishSksContext *psc;
1453 struct GNUNET_CRYPTO_AesSessionKey sk;
1454 struct GNUNET_CRYPTO_AesInitializationVector iv;
1455 struct GNUNET_FS_Uri *sks_uri;
1463 struct SBlock *sb_enc;
1465 GNUNET_HashCode key; /* hash of thisId = key */
1466 GNUNET_HashCode id; /* hash of hc = identifier */
1468 uris = GNUNET_FS_uri_to_string (uri);
1469 slen = strlen (uris) + 1;
1470 idlen = strlen (identifier);
1473 nidlen = strlen (update) + 1;
1474 mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1475 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1477 size = sizeof (struct SBlock) + slen + nidlen + mdsize;
1478 if (size > MAX_SBLOCK_SIZE)
1480 size = MAX_SBLOCK_SIZE;
1481 mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
1483 sb = GNUNET_malloc (sizeof (struct SBlock) + size);
1484 dest = (char *) &sb[1];
1485 memcpy (dest, update, nidlen);
1487 memcpy (dest, uris, slen);
1489 mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1492 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1500 _("Internal error."));
1503 size = sizeof (struct SBlock) + mdsize + slen + nidlen;
1504 sb_enc = GNUNET_malloc (sizeof (struct SBlock) + size);
1505 GNUNET_CRYPTO_hash (identifier, idlen, &key);
1506 GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
1507 sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
1508 sks_uri->type = sks;
1509 GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
1510 GNUNET_CRYPTO_hash (&sb_enc->subspace,
1511 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1512 &sks_uri->data.sks.namespace);
1513 sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
1514 GNUNET_CRYPTO_hash_xor (&id,
1515 &sks_uri->data.sks.namespace,
1516 &sb_enc->identifier);
1517 GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
1518 GNUNET_CRYPTO_aes_encrypt (&sb[1],
1519 size - sizeof (struct SBlock),
1524 sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
1525 sb_enc->purpose.size = htonl(slen + mdsize + nidlen
1526 + sizeof(struct SBlock)
1527 - sizeof(struct GNUNET_CRYPTO_RsaSignature));
1528 GNUNET_assert (GNUNET_OK ==
1529 GNUNET_CRYPTO_rsa_sign (namespace->key,
1531 &sb_enc->signature));
1532 psc = GNUNET_malloc (sizeof(struct PublishSksContext));
1535 psc->cont_cls = cont_cls;
1536 if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1538 GNUNET_free (sb_enc);
1544 psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
1545 if (NULL == psc->dsh)
1547 GNUNET_free (sb_enc);
1550 _("Failed to connect to datastore."));
1554 GNUNET_DATASTORE_put (psc->dsh,
1559 GNUNET_DATASTORE_BLOCKTYPE_SBLOCK,
1563 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1566 GNUNET_free (sb_enc);
1570 /* end of fs_publish.c */