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 * - indexing cleanup: unindex on failure (can wait)
30 * - persistence support (can wait)
31 * - datastore reservation support (optimization)
32 * - location URIs (publish with anonymity-level zero)
36 #include "gnunet_constants.h"
37 #include "gnunet_signatures.h"
38 #include "gnunet_util_lib.h"
39 #include "gnunet_fs_service.h"
43 #define DEBUG_PUBLISH GNUNET_NO
46 * Maximum allowed size for a KBlock.
48 #define MAX_KBLOCK_SIZE 60000
51 * Maximum allowed size for an SBlock.
53 #define MAX_SBLOCK_SIZE 60000
56 * Main function that performs the upload.
57 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload
58 * @param tc task context
62 const struct GNUNET_SCHEDULER_TaskContext *tc);
66 * Context for "ds_put_cont".
71 * Current publishing context.
73 struct GNUNET_FS_PublishContext *sc;
76 * Specific file with the block.
78 struct GNUNET_FS_FileInformation *p;
81 * Function to run next, if any (can be NULL).
83 GNUNET_SCHEDULER_Task cont;
93 * Fill in all of the generic fields for
96 * @param pi structure to fill in
97 * @param sc overall publishing context
98 * @param p file information for the file being published
99 * @param offset where in the file are we so far
102 make_publish_status (struct GNUNET_FS_ProgressInfo *pi,
103 struct GNUNET_FS_PublishContext *sc,
104 const struct GNUNET_FS_FileInformation *p,
107 pi->value.publish.sc = sc;
108 pi->value.publish.fi = p;
109 pi->value.publish.cctx
111 pi->value.publish.pctx
112 = (NULL == p->dir) ? NULL : p->dir->client_info;
113 pi->value.publish.filename
114 = (p->is_directory) ? p->data.dir.dirname : p->data.file.filename;
115 pi->value.publish.size
116 = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size;
117 pi->value.publish.eta
118 = GNUNET_TIME_calculate_eta (p->start_time,
120 pi->value.publish.size);
121 pi->value.publish.completed = offset;
122 pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (p->start_time);
123 pi->value.publish.anonymity = p->anonymity;
128 * Cleanup the publish context, we're done
131 * @param sc struct to clean up after
134 publish_cleanup (struct GNUNET_FS_PublishContext *sc)
136 GNUNET_FS_file_information_destroy (sc->fi, NULL, NULL);
137 if (sc->namespace != NULL)
138 GNUNET_FS_namespace_delete (sc->namespace, GNUNET_NO);
139 GNUNET_free_non_null (sc->nid);
140 GNUNET_free_non_null (sc->nuid);
141 GNUNET_DATASTORE_disconnect (sc->dsh, GNUNET_NO);
147 * Function called by the datastore API with
148 * the result from the PUT request.
150 * @param cls our closure
151 * @param success GNUNET_OK on success
152 * @param msg error message (or NULL)
155 ds_put_cont (void *cls,
159 struct PutContCtx *pcc = cls;
160 struct GNUNET_FS_ProgressInfo pi;
162 if (GNUNET_SYSERR == pcc->sc->in_network_wait)
164 /* we were aborted in the meantime,
166 publish_cleanup (pcc->sc);
169 GNUNET_assert (GNUNET_YES == pcc->sc->in_network_wait);
170 pcc->sc->in_network_wait = GNUNET_NO;
171 if (GNUNET_OK != success)
173 GNUNET_asprintf (&pcc->p->emsg,
174 _("Upload failed: %s"),
176 GNUNET_FS_file_information_sync (pcc->p);
177 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
178 make_publish_status (&pi, pcc->sc, pcc->p, 0);
179 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
180 pi.value.publish.specifics.error.message = pcc->p->emsg;
182 = pcc->sc->h->upcb (pcc->sc->h->upcb_cls,
185 GNUNET_FS_file_information_sync (pcc->p);
186 if (NULL != pcc->cont)
188 = GNUNET_SCHEDULER_add_delayed (pcc->sc->h->sched,
190 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
191 GNUNET_SCHEDULER_NO_TASK,
192 GNUNET_TIME_UNIT_ZERO,
200 * Generate the callback that signals clients
201 * that a file (or directory) has been completely
204 * @param p the completed upload
205 * @param sc context of the publication
208 signal_publish_completion (struct GNUNET_FS_FileInformation *p,
209 struct GNUNET_FS_PublishContext *sc)
211 struct GNUNET_FS_ProgressInfo pi;
213 pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED;
214 make_publish_status (&pi, sc, p,
215 GNUNET_ntohll (p->chk_uri->data.chk.file_length));
216 pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO;
217 pi.value.publish.specifics.completed.chk_uri = p->chk_uri;
219 = sc->h->upcb (sc->h->upcb_cls,
225 * Generate the callback that signals clients
226 * that a file (or directory) has encountered
227 * a problem during publication.
229 * @param p the upload that had trouble
230 * @param sc context of the publication
231 * @param emsg error message
234 signal_publish_error (struct GNUNET_FS_FileInformation *p,
235 struct GNUNET_FS_PublishContext *sc,
238 struct GNUNET_FS_ProgressInfo pi;
240 p->emsg = GNUNET_strdup (emsg);
241 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
242 make_publish_status (&pi, sc, p, 0);
243 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
244 pi.value.publish.specifics.error.message =emsg;
246 = sc->h->upcb (sc->h->upcb_cls,
252 * We've finished publishing the SBlock as part of a larger upload.
253 * Check the result and complete the larger upload.
255 * @param cls the "struct GNUNET_FS_PublishContext*" of the larger upload
256 * @param uri URI of the published SBlock
257 * @param emsg NULL on success, otherwise error message
260 publish_sblocks_cont (void *cls,
261 const struct GNUNET_FS_Uri *uri,
264 struct GNUNET_FS_PublishContext *sc = cls;
267 signal_publish_error (sc->fi,
272 // FIXME: release the datastore reserve here!
273 signal_publish_completion (sc->fi, sc);
274 sc->all_done = GNUNET_YES;
279 * We are almost done publishing the structure,
280 * add SBlocks (if needed).
282 * @param sc overall upload data
285 publish_sblock (struct GNUNET_FS_PublishContext *sc)
287 if (NULL != sc->namespace)
288 GNUNET_FS_publish_sks (sc->h,
294 sc->fi->expirationTime,
298 &publish_sblocks_cont,
301 publish_sblocks_cont (sc, NULL, NULL);
306 * We've finished publishing a KBlock
307 * as part of a larger upload. Check
308 * the result and continue the larger
311 * @param cls the "struct GNUNET_FS_PublishContext*"
312 * of the larger upload
313 * @param uri URI of the published blocks
314 * @param emsg NULL on success, otherwise error message
317 publish_kblocks_cont (void *cls,
318 const struct GNUNET_FS_Uri *uri,
321 struct GNUNET_FS_PublishContext *sc = cls;
322 struct GNUNET_FS_FileInformation *p = sc->fi_pos;
326 signal_publish_error (p, sc, emsg);
328 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
330 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
331 GNUNET_SCHEDULER_NO_TASK,
332 GNUNET_TIME_UNIT_ZERO,
337 GNUNET_FS_file_information_sync (p);
339 signal_publish_completion (p, sc);
340 /* move on to next file */
342 sc->fi_pos = p->next;
346 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
348 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
349 GNUNET_SCHEDULER_NO_TASK,
350 GNUNET_TIME_UNIT_ZERO,
357 * Function called by the tree encoder to obtain
358 * a block of plaintext data (for the lowest level
361 * @param cls our publishing context
362 * @param offset identifies which block to get
363 * @param max (maximum) number of bytes to get; returning
364 * fewer will also cause errors
365 * @param buf where to copy the plaintext buffer
366 * @param emsg location to store an error message (on error)
367 * @return number of bytes copied to buf, 0 on error
370 block_reader (void *cls,
376 struct GNUNET_FS_PublishContext *sc = cls;
377 struct GNUNET_FS_FileInformation *p;
384 pt_size = GNUNET_MIN(max,
385 p->data.dir.dir_size - offset);
386 dd = p->data.dir.dir_data;
393 pt_size = GNUNET_MIN(max,
394 p->data.file.file_size - offset);
396 return 0; /* calling reader with pt_size==0
397 might free buf, so don't! */
399 p->data.file.reader (p->data.file.reader_cls,
411 * The tree encoder has finished processing a
412 * file. Call it's finish method and deal with
415 * @param cls our publishing context
416 * @param tc scheduler's task context (not used)
419 encode_cont (void *cls,
420 const struct GNUNET_SCHEDULER_TaskContext *tc)
422 struct GNUNET_FS_PublishContext *sc = cls;
423 struct GNUNET_FS_FileInformation *p;
424 struct GNUNET_FS_ProgressInfo pi;
428 GNUNET_FS_tree_encoder_finish (p->te,
434 GNUNET_asprintf (&p->emsg,
435 _("Upload failed: %s"),
438 GNUNET_FS_file_information_sync (p);
439 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
440 make_publish_status (&pi, sc, p, 0);
441 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
442 pi.value.publish.specifics.error.message = p->emsg;
444 = sc->h->upcb (sc->h->upcb_cls,
447 /* continue with main */
449 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
451 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
452 GNUNET_SCHEDULER_NO_TASK,
453 GNUNET_TIME_UNIT_ZERO,
460 * Function called asking for the current (encoded)
461 * block to be processed. After processing the
462 * client should either call "GNUNET_FS_tree_encode_next"
463 * or (on error) "GNUNET_FS_tree_encode_finish".
466 * @param query the query for the block (key for lookup in the datastore)
467 * @param offset offset of the block in the file
468 * @param type type of the block (IBLOCK or DBLOCK)
469 * @param block the (encrypted) block
470 * @param block_size size of block (in bytes)
473 block_proc (void *cls,
474 const GNUNET_HashCode *query,
480 struct GNUNET_FS_PublishContext *sc = cls;
481 struct GNUNET_FS_FileInformation *p;
482 struct PutContCtx * dpc_cls;
483 struct OnDemandBlock odb;
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 "Publishing block `%s' for offset %llu with size %u\n",
489 (unsigned long long) offset,
490 (unsigned int) block_size);
496 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
498 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
499 GNUNET_SCHEDULER_NO_TASK,
500 GNUNET_TIME_UNIT_ZERO,
506 GNUNET_assert (GNUNET_NO == sc->in_network_wait);
507 sc->in_network_wait = GNUNET_YES;
508 dpc_cls = GNUNET_malloc(sizeof(struct PutContCtx));
509 dpc_cls->cont = &do_upload;
510 dpc_cls->cont_cls = sc;
513 if ( (p->is_directory) &&
514 (p->data.file.do_index) &&
515 (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) )
518 odb.file_id = p->data.file.file_id;
519 GNUNET_DATASTORE_put (sc->dsh,
522 sizeof(struct OnDemandBlock),
524 GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND,
528 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
533 GNUNET_DATASTORE_put (sc->dsh,
542 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
549 * Function called with information about our
550 * progress in computing the tree encoding.
553 * @param offset where are we in the file
554 * @param pt_block plaintext of the currently processed block
555 * @param pt_size size of pt_block
556 * @param depth depth of the block in the tree
559 progress_proc (void *cls,
561 const void *pt_block,
565 struct GNUNET_FS_PublishContext *sc = cls;
566 struct GNUNET_FS_FileInformation *p;
567 struct GNUNET_FS_ProgressInfo pi;
570 pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS;
571 make_publish_status (&pi, sc, p, offset);
572 pi.value.publish.specifics.progress.data = pt_block;
573 pi.value.publish.specifics.progress.offset = offset;
574 pi.value.publish.specifics.progress.data_len = pt_size;
575 pi.value.publish.specifics.progress.depth = depth;
577 = sc->h->upcb (sc->h->upcb_cls,
583 * We are uploading a file or directory; load (if necessary) the next
584 * block into memory, encrypt it and send it to the FS service. Then
585 * continue with the main task.
587 * @param sc overall upload data
590 publish_content (struct GNUNET_FS_PublishContext *sc)
592 struct GNUNET_FS_FileInformation *p;
594 struct GNUNET_FS_DirectoryBuilder *db;
595 struct GNUNET_FS_FileInformation *dirpos;
604 db = GNUNET_FS_directory_builder_create (p->meta);
605 dirpos = p->data.dir.entries;
606 while (NULL != dirpos)
608 if (dirpos->is_directory)
610 raw_data = dirpos->data.dir.dir_data;
611 dirpos->data.dir.dir_data = NULL;
616 if ( (dirpos->data.file.file_size < MAX_INLINE_SIZE) &&
617 (dirpos->data.file.file_size > 0) )
619 raw_data = GNUNET_malloc (dirpos->data.file.file_size);
621 if (dirpos->data.file.file_size !=
622 dirpos->data.file.reader (dirpos->data.file.reader_cls,
624 dirpos->data.file.file_size,
628 GNUNET_free_non_null (emsg);
629 GNUNET_free (raw_data);
634 GNUNET_FS_directory_builder_add (db,
638 GNUNET_free_non_null (raw_data);
639 dirpos = dirpos->next;
641 GNUNET_FS_directory_builder_finish (db,
642 &p->data.dir.dir_size,
643 &p->data.dir.dir_data);
645 size = (p->is_directory)
646 ? p->data.dir.dir_size
647 : p->data.file.file_size;
648 p->te = GNUNET_FS_tree_encoder_create (sc->h,
657 GNUNET_FS_tree_encoder_next (p->te);
662 * Process the response (or lack thereof) from
663 * the "fs" service to our 'start index' request.
665 * @param cls closure (of type "struct GNUNET_FS_PublishContext*"_)
666 * @param msg the response we got
669 process_index_start_response (void *cls,
670 const struct GNUNET_MessageHeader *msg)
672 struct GNUNET_FS_PublishContext *sc = cls;
673 struct GNUNET_FS_FileInformation *p;
677 GNUNET_CLIENT_disconnect (sc->client);
682 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
683 _("Can not index file `%s': %s. Will try to insert instead.\n"),
684 p->data.file.filename,
685 _("timeout on index-start request to `fs' service"));
686 p->data.file.do_index = GNUNET_NO;
687 publish_content (sc);
690 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK)
692 msize = ntohs (msg->size);
693 emsg = (const char *) &msg[1];
694 if ( (msize <= sizeof (struct GNUNET_MessageHeader)) ||
695 (emsg[msize - sizeof(struct GNUNET_MessageHeader) - 1] != '\0') )
696 emsg = gettext_noop ("unknown error");
697 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
698 _("Can not index file `%s': %s. Will try to insert instead.\n"),
699 p->data.file.filename,
701 p->data.file.do_index = GNUNET_NO;
702 publish_content (sc);
705 /* success! continue with indexing */
706 publish_content (sc);
711 * Function called once the hash computation over an
712 * indexed file has completed.
714 * @param cls closure, our publishing context
715 * @param res resulting hash, NULL on error
718 hash_for_index_cb (void *cls,
719 const GNUNET_HashCode *
722 struct GNUNET_FS_PublishContext *sc = cls;
723 struct GNUNET_FS_FileInformation *p;
724 struct IndexStartMessage *ism;
726 struct GNUNET_CLIENT_Connection *client;
733 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
734 _("Can not index file `%s': %s. Will try to insert instead.\n"),
735 p->data.file.filename,
736 _("failed to compute hash"));
737 p->data.file.do_index = GNUNET_NO;
738 publish_content (sc);
741 slen = strlen (p->data.file.filename) + 1;
742 if (slen > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof(struct IndexStartMessage))
744 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
745 _("Can not index file `%s': %s. Will try to insert instead.\n"),
746 p->data.file.filename,
747 _("filename too long"));
748 p->data.file.do_index = GNUNET_NO;
749 publish_content (sc);
752 client = GNUNET_CLIENT_connect (sc->h->sched,
757 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
758 _("Can not index file `%s': %s. Will try to insert instead.\n"),
759 p->data.file.filename,
760 _("could not connect to `fs' service"));
761 p->data.file.do_index = GNUNET_NO;
762 publish_content (sc);
765 p->data.file.file_id = *res;
766 ism = GNUNET_malloc (sizeof(struct IndexStartMessage) +
768 ism->header.size = htons(sizeof(struct IndexStartMessage) +
770 ism->header.type = htons(GNUNET_MESSAGE_TYPE_FS_INDEX_START);
772 GNUNET_DISK_file_get_identifiers (p->data.file.filename,
776 ism->device = htonl (dev);
777 ism->inode = GNUNET_htonll(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,
847 sc->all_done = GNUNET_YES;
850 /* handle completion */
851 if (NULL != p->chk_uri)
853 /* upload of "p" complete, publish KBlocks! */
854 GNUNET_FS_publish_ksk (sc->h,
862 &publish_kblocks_cont,
866 if ( (!p->is_directory) &&
867 (p->data.file.do_index) )
869 if (NULL == p->data.file.filename)
871 p->data.file.do_index = GNUNET_NO;
872 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
873 _("Can not index file `%s': %s. Will try to insert instead.\n"),
875 _("needs to be an actual file"));
876 publish_content (sc);
879 GNUNET_CRYPTO_hash_file (sc->h->sched,
880 GNUNET_SCHEDULER_PRIORITY_IDLE,
882 p->data.file.filename,
888 publish_content (sc);
893 * Signal the FS's progress function that we are starting
896 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
897 * @param fi the entry in the publish-structure
898 * @param length length of the file or directory
899 * @param meta metadata for the file or directory (can be modified)
900 * @param uri pointer to the keywords that will be used for this entry (can be modified)
901 * @param anonymity pointer to selected anonymity level (can be modified)
902 * @param priority pointer to selected priority (can be modified)
903 * @param expirationTime pointer to selected expiration time (can be modified)
904 * @param client_info pointer to client context set upon creation (can be modified)
905 * @return GNUNET_OK to continue (always)
908 fip_signal_start(void *cls,
909 struct GNUNET_FS_FileInformation *fi,
911 struct GNUNET_CONTAINER_MetaData *meta,
912 struct GNUNET_FS_Uri **uri,
915 struct GNUNET_TIME_Absolute *expirationTime,
918 struct GNUNET_FS_PublishContext *sc = cls;
919 struct GNUNET_FS_ProgressInfo pi;
921 pi.status = GNUNET_FS_STATUS_PUBLISH_START;
922 make_publish_status (&pi, sc, fi, 0);
923 *client_info = sc->h->upcb (sc->h->upcb_cls,
930 * Publish a file or directory.
932 * @param h handle to the file sharing subsystem
933 * @param fi information about the file or directory structure to publish
934 * @param namespace namespace to publish the file in, NULL for no namespace
935 * @param nid identifier to use for the publishd content in the namespace
936 * (can be NULL, must be NULL if namespace is NULL)
937 * @param nuid update-identifier that will be used for future updates
938 * (can be NULL, must be NULL if namespace or nid is NULL)
939 * @param options options for the publication
940 * @return context that can be used to control the publish operation
942 struct GNUNET_FS_PublishContext *
943 GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h,
944 struct GNUNET_FS_FileInformation *fi,
945 struct GNUNET_FS_Namespace *namespace,
948 enum GNUNET_FS_PublishOptions options)
950 struct GNUNET_FS_PublishContext *ret;
951 struct GNUNET_DATASTORE_Handle *dsh;
953 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
955 dsh = GNUNET_DATASTORE_connect (h->cfg,
964 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext));
968 ret->namespace = namespace;
969 if (namespace != NULL)
972 GNUNET_assert (NULL != nid);
973 ret->nid = GNUNET_strdup (nid);
975 ret->nuid = GNUNET_strdup (nuid);
977 // FIXME: make upload persistent!
980 GNUNET_FS_file_information_inspect (ret->fi,
983 ret->fi_pos = ret->fi;
985 // FIXME: calculate space needed for "fi"
986 // and reserve as first task (then trigger
987 // "do_upload" from that continuation)!
989 = GNUNET_SCHEDULER_add_delayed (h->sched,
991 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
992 GNUNET_SCHEDULER_NO_TASK,
993 GNUNET_TIME_UNIT_ZERO,
1001 * Signal the FS's progress function that we are stopping
1004 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
1005 * @param fi the entry in the publish-structure
1006 * @param length length of the file or directory
1007 * @param meta metadata for the file or directory (can be modified)
1008 * @param uri pointer to the keywords that will be used for this entry (can be modified)
1009 * @param anonymity pointer to selected anonymity level (can be modified)
1010 * @param priority pointer to selected priority (can be modified)
1011 * @param expirationTime pointer to selected expiration time (can be modified)
1012 * @param client_info pointer to client context set upon creation (can be modified)
1013 * @return GNUNET_OK to continue (always)
1016 fip_signal_stop(void *cls,
1017 struct GNUNET_FS_FileInformation *fi,
1019 struct GNUNET_CONTAINER_MetaData *meta,
1020 struct GNUNET_FS_Uri **uri,
1021 uint32_t *anonymity,
1023 struct GNUNET_TIME_Absolute *expirationTime,
1026 struct GNUNET_FS_PublishContext*sc = cls;
1027 struct GNUNET_FS_ProgressInfo pi;
1030 off = (fi->chk_uri == NULL) ? 0 : length;
1031 pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED;
1032 make_publish_status (&pi, sc, fi, off);
1033 GNUNET_break (NULL ==
1034 sc->h->upcb (sc->h->upcb_cls,
1036 *client_info = NULL;
1042 * Stop an upload. Will abort incomplete uploads (but
1043 * not remove blocks that have already been publishd) or
1044 * simply clean up the state for completed uploads.
1045 * Must NOT be called from within the event callback!
1047 * @param sc context for the upload to stop
1050 GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *sc)
1052 if (GNUNET_SCHEDULER_NO_TASK != sc->upload_task)
1053 GNUNET_SCHEDULER_cancel (sc->h->sched, sc->upload_task);
1055 GNUNET_assert (sc->all_done == GNUNET_YES);
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.
1141 * Priority for the KBlocks.
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 the actual
1197 * publishing operation (iterating over all of the keywords).
1199 * @param cls closure of type "struct PublishKskContext*"
1203 publish_ksk_cont (void *cls,
1204 const struct GNUNET_SCHEDULER_TaskContext *tc)
1206 struct PublishKskContext *pkc = cls;
1207 const char *keyword;
1208 GNUNET_HashCode key;
1209 GNUNET_HashCode query;
1210 struct GNUNET_CRYPTO_AesSessionKey skey;
1211 struct GNUNET_CRYPTO_AesInitializationVector iv;
1212 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
1215 if ( (pkc->i == pkc->ksk_uri->data.ksk.keywordCount) ||
1216 (NULL == pkc->dsh) )
1218 if (NULL != pkc->dsh)
1219 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1220 GNUNET_free (pkc->cpy);
1221 GNUNET_free (pkc->kb);
1222 pkc->cont (pkc->cont_cls,
1225 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1229 keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
1230 /* first character of keyword indicates if it is
1231 mandatory or not -- ignore for hashing */
1232 GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
1233 GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
1234 GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1],
1235 pkc->slen + pkc->mdsize,
1239 pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
1240 GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace);
1241 GNUNET_CRYPTO_hash (&pkc->cpy->keyspace,
1242 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1244 GNUNET_assert (GNUNET_OK ==
1245 GNUNET_CRYPTO_rsa_sign (pk,
1247 &pkc->cpy->signature));
1248 GNUNET_CRYPTO_rsa_key_free (pk);
1249 GNUNET_DATASTORE_put (pkc->dsh,
1253 sizeof (struct KBlock) +
1256 GNUNET_DATASTORE_BLOCKTYPE_KBLOCK,
1259 pkc->expirationTime,
1260 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1267 * Publish a CHK under various keywords on GNUnet.
1269 * @param h handle to the file sharing subsystem
1270 * @param ksk_uri keywords to use
1271 * @param meta metadata to use
1272 * @param uri URI to refer to in the KBlock
1273 * @param expirationTime when the KBlock expires
1274 * @param anonymity anonymity level for the KBlock
1275 * @param priority priority for the KBlock
1276 * @param options publication options
1277 * @param cont continuation
1278 * @param cont_cls closure for cont
1281 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
1282 struct GNUNET_FS_Uri *ksk_uri,
1283 struct GNUNET_CONTAINER_MetaData *meta,
1284 struct GNUNET_FS_Uri *uri,
1285 struct GNUNET_TIME_Absolute expirationTime,
1288 enum GNUNET_FS_PublishOptions options,
1289 GNUNET_FS_PublishContinuation cont,
1292 struct PublishKskContext *pkc;
1297 pkc = GNUNET_malloc (sizeof (struct PublishKskContext));
1299 pkc->expirationTime = expirationTime;
1300 pkc->anonymity = anonymity;
1301 pkc->priority = priority;
1303 pkc->cont_cls = cont_cls;
1304 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1306 pkc->dsh = GNUNET_DATASTORE_connect (h->cfg,
1308 if (pkc->dsh == NULL)
1310 cont (cont_cls, NULL, _("Could not connect to datastore."));
1315 pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1316 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1317 GNUNET_assert (pkc->mdsize >= 0);
1318 uris = GNUNET_FS_uri_to_string (uri);
1319 pkc->slen = strlen (uris) + 1;
1320 size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen;
1321 if (size > MAX_KBLOCK_SIZE)
1323 size = MAX_KBLOCK_SIZE;
1324 pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen;
1326 pkc->kb = GNUNET_malloc (size);
1327 kbe = (char *) &pkc->kb[1];
1328 memcpy (kbe, uris, pkc->slen);
1330 pkc->mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1333 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1334 if (pkc->mdsize == -1)
1337 GNUNET_free (pkc->kb);
1338 if (pkc->dsh != NULL)
1339 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1340 cont (cont_cls, NULL, _("Internal error."));
1344 size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize;
1346 pkc->cpy = GNUNET_malloc (size);
1347 pkc->cpy->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
1348 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
1351 pkc->cpy->purpose.purpose = htonl(GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK);
1352 pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
1353 GNUNET_SCHEDULER_add_continuation (h->sched,
1357 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1362 * Context for the SKS publication.
1364 struct PublishSksContext
1368 * Global FS context.
1370 struct GNUNET_FS_Uri *uri;
1373 * Handle to the datastore.
1375 struct GNUNET_DATASTORE_Handle *dsh;
1378 * Function to call once we're done.
1380 GNUNET_FS_PublishContinuation cont;
1391 * Function called by the datastore API with
1392 * the result from the PUT (SBlock) request.
1394 * @param cls closure of type "struct PublishSksContext*"
1395 * @param success GNUNET_OK on success
1396 * @param msg error message (or NULL)
1399 sb_put_cont (void *cls,
1403 struct PublishSksContext *psc = cls;
1405 if (NULL != psc->dsh)
1406 GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
1407 if (GNUNET_OK != success)
1408 psc->cont (psc->cont_cls,
1412 psc->cont (psc->cont_cls,
1415 GNUNET_FS_uri_destroy (psc->uri);
1421 * Publish an SBlock on GNUnet.
1423 * @param h handle to the file sharing subsystem
1424 * @param namespace namespace to publish in
1425 * @param identifier identifier to use
1426 * @param update update identifier to use
1427 * @param meta metadata to use
1428 * @param uri URI to refer to in the SBlock
1429 * @param expirationTime when the SBlock expires
1430 * @param anonymity anonymity level for the SBlock
1431 * @param priority priority for the SBlock
1432 * @param options publication options
1433 * @param cont continuation
1434 * @param cont_cls closure for cont
1437 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
1438 struct GNUNET_FS_Namespace *namespace,
1439 const char *identifier,
1441 struct GNUNET_CONTAINER_MetaData *meta,
1442 struct GNUNET_FS_Uri *uri,
1443 struct GNUNET_TIME_Absolute expirationTime,
1446 enum GNUNET_FS_PublishOptions options,
1447 GNUNET_FS_PublishContinuation cont,
1450 struct PublishSksContext *psc;
1451 struct GNUNET_CRYPTO_AesSessionKey sk;
1452 struct GNUNET_CRYPTO_AesInitializationVector iv;
1453 struct GNUNET_FS_Uri *sks_uri;
1461 struct SBlock *sb_enc;
1463 GNUNET_HashCode key; /* hash of thisId = key */
1464 GNUNET_HashCode id; /* hash of hc = identifier */
1466 uris = GNUNET_FS_uri_to_string (uri);
1467 slen = strlen (uris) + 1;
1468 idlen = strlen (identifier);
1471 nidlen = strlen (update) + 1;
1472 mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1473 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1475 size = sizeof (struct SBlock) + slen + nidlen + mdsize;
1476 if (size > MAX_SBLOCK_SIZE)
1478 size = MAX_SBLOCK_SIZE;
1479 mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
1481 sb = GNUNET_malloc (sizeof (struct SBlock) + size);
1482 dest = (char *) &sb[1];
1483 memcpy (dest, update, nidlen);
1485 memcpy (dest, uris, slen);
1487 mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1490 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1498 _("Internal error."));
1501 size = sizeof (struct SBlock) + mdsize + slen + nidlen;
1502 sb_enc = GNUNET_malloc (sizeof (struct SBlock) + size);
1503 GNUNET_CRYPTO_hash (identifier, idlen, &key);
1504 GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
1505 sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
1506 sks_uri->type = sks;
1507 GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
1508 GNUNET_CRYPTO_hash (&sb_enc->subspace,
1509 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1510 &sks_uri->data.sks.namespace);
1511 sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
1512 GNUNET_CRYPTO_hash_xor (&id,
1513 &sks_uri->data.sks.namespace,
1514 &sb_enc->identifier);
1515 GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
1516 GNUNET_CRYPTO_aes_encrypt (&sb[1],
1517 size - sizeof (struct SBlock),
1522 sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
1523 sb_enc->purpose.size = htonl(slen + mdsize + nidlen
1524 + sizeof(struct SBlock)
1525 - sizeof(struct GNUNET_CRYPTO_RsaSignature));
1526 GNUNET_assert (GNUNET_OK ==
1527 GNUNET_CRYPTO_rsa_sign (namespace->key,
1529 &sb_enc->signature));
1530 psc = GNUNET_malloc (sizeof(struct PublishSksContext));
1533 psc->cont_cls = cont_cls;
1534 if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1536 GNUNET_free (sb_enc);
1542 psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
1543 if (NULL == psc->dsh)
1545 GNUNET_free (sb_enc);
1548 _("Failed to connect to datastore."));
1552 GNUNET_DATASTORE_put (psc->dsh,
1557 GNUNET_DATASTORE_BLOCKTYPE_SBLOCK,
1561 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1564 GNUNET_free (sb_enc);
1568 /* end of fs_publish.c */