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_YES
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 ctx initial value to use for the '*ctx'
934 * in the callback (for the GNUNET_FS_STATUS_PUBLISH_START event).
935 * @param fi information about the file or directory structure to publish
936 * @param namespace namespace to publish the file in, NULL for no namespace
937 * @param nid identifier to use for the publishd content in the namespace
938 * (can be NULL, must be NULL if namespace is NULL)
939 * @param nuid update-identifier that will be used for future updates
940 * (can be NULL, must be NULL if namespace or nid is NULL)
941 * @param options options for the publication
942 * @return context that can be used to control the publish operation
944 struct GNUNET_FS_PublishContext *
945 GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h,
947 struct GNUNET_FS_FileInformation *fi,
948 struct GNUNET_FS_Namespace *namespace,
951 enum GNUNET_FS_PublishOptions options)
953 struct GNUNET_FS_PublishContext *ret;
954 struct GNUNET_DATASTORE_Handle *dsh;
956 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
958 dsh = GNUNET_DATASTORE_connect (h->cfg,
967 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext));
970 ret->client_ctx = ctx;
972 ret->namespace = namespace;
973 if (namespace != NULL)
976 GNUNET_assert (NULL != nid);
977 ret->nid = GNUNET_strdup (nid);
979 ret->nuid = GNUNET_strdup (nuid);
981 // FIXME: make upload persistent!
984 GNUNET_FS_file_information_inspect (ret->fi,
987 ret->fi_pos = ret->fi;
989 // FIXME: calculate space needed for "fi"
990 // and reserve as first task (then trigger
991 // "do_upload" from that continuation)!
993 = GNUNET_SCHEDULER_add_delayed (h->sched,
995 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
996 GNUNET_SCHEDULER_NO_TASK,
997 GNUNET_TIME_UNIT_ZERO,
1005 * Signal the FS's progress function that we are stopping
1008 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
1009 * @param fi the entry in the publish-structure
1010 * @param length length of the file or directory
1011 * @param meta metadata for the file or directory (can be modified)
1012 * @param uri pointer to the keywords that will be used for this entry (can be modified)
1013 * @param anonymity pointer to selected anonymity level (can be modified)
1014 * @param priority pointer to selected priority (can be modified)
1015 * @param expirationTime pointer to selected expiration time (can be modified)
1016 * @param client_info pointer to client context set upon creation (can be modified)
1017 * @return GNUNET_OK to continue (always)
1020 fip_signal_stop(void *cls,
1021 struct GNUNET_FS_FileInformation *fi,
1023 struct GNUNET_CONTAINER_MetaData *meta,
1024 struct GNUNET_FS_Uri **uri,
1025 uint32_t *anonymity,
1027 struct GNUNET_TIME_Absolute *expirationTime,
1030 struct GNUNET_FS_PublishContext*sc = cls;
1031 struct GNUNET_FS_ProgressInfo pi;
1034 off = (fi->chk_uri == NULL) ? 0 : length;
1035 pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED;
1036 make_publish_status (&pi, sc, fi, off);
1037 GNUNET_break (NULL ==
1038 sc->h->upcb (sc->h->upcb_cls,
1040 *client_info = NULL;
1046 * Stop an upload. Will abort incomplete uploads (but
1047 * not remove blocks that have already been publishd) or
1048 * simply clean up the state for completed uploads.
1049 * Must NOT be called from within the event callback!
1051 * @param sc context for the upload to stop
1054 GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *sc)
1056 if (GNUNET_SCHEDULER_NO_TASK != sc->upload_task)
1057 GNUNET_SCHEDULER_cancel (sc->h->sched, sc->upload_task);
1059 GNUNET_assert (sc->all_done == GNUNET_YES);
1060 // FIXME: remove from persistence DB (?) --- think more about
1061 // shutdown / persistent-resume APIs!!!
1062 GNUNET_FS_file_information_inspect (sc->fi,
1065 if (GNUNET_YES == sc->in_network_wait)
1067 sc->in_network_wait = GNUNET_SYSERR;
1070 publish_cleanup (sc);
1075 * Context for the KSK publication.
1077 struct PublishKskContext
1083 struct GNUNET_FS_Uri *ksk_uri;
1086 * Global FS context.
1088 struct GNUNET_FS_Handle *h;
1091 * The master block that we are sending
1092 * (in plaintext), has "mdsize+slen" more
1093 * bytes than the struct would suggest.
1098 * Buffer of the same size as "kb" for
1099 * the encrypted version.
1104 * Handle to the datastore, NULL if we are just
1107 struct GNUNET_DATASTORE_Handle *dsh;
1110 * Function to call once we're done.
1112 GNUNET_FS_PublishContinuation cont;
1120 * When should the KBlocks expire?
1122 struct GNUNET_TIME_Absolute expirationTime;
1125 * Size of the serialized metadata.
1130 * Size of the (CHK) URI as a string.
1135 * Keyword that we are currently processing.
1140 * Anonymity level for the KBlocks.
1145 * Priority for the KBlocks.
1152 * Continuation of "GNUNET_FS_publish_ksk" that performs
1153 * the actual publishing operation (iterating over all
1156 * @param cls closure of type "struct PublishKskContext*"
1160 publish_ksk_cont (void *cls,
1161 const struct GNUNET_SCHEDULER_TaskContext *tc);
1165 * Function called by the datastore API with
1166 * the result from the PUT request.
1168 * @param cls closure of type "struct PublishKskContext*"
1169 * @param success GNUNET_OK on success
1170 * @param msg error message (or NULL)
1173 kb_put_cont (void *cls,
1177 struct PublishKskContext *pkc = cls;
1179 if (GNUNET_OK != success)
1181 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1182 GNUNET_free (pkc->cpy);
1183 GNUNET_free (pkc->kb);
1184 pkc->cont (pkc->cont_cls,
1187 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1191 GNUNET_SCHEDULER_add_continuation (pkc->h->sched,
1195 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1200 * Continuation of "GNUNET_FS_publish_ksk" that performs the actual
1201 * publishing operation (iterating over all of the keywords).
1203 * @param cls closure of type "struct PublishKskContext*"
1207 publish_ksk_cont (void *cls,
1208 const struct GNUNET_SCHEDULER_TaskContext *tc)
1210 struct PublishKskContext *pkc = cls;
1211 const char *keyword;
1212 GNUNET_HashCode key;
1213 GNUNET_HashCode query;
1214 struct GNUNET_CRYPTO_AesSessionKey skey;
1215 struct GNUNET_CRYPTO_AesInitializationVector iv;
1216 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
1219 if ( (pkc->i == pkc->ksk_uri->data.ksk.keywordCount) ||
1220 (NULL == pkc->dsh) )
1222 if (NULL != pkc->dsh)
1223 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1224 GNUNET_free (pkc->cpy);
1225 GNUNET_free (pkc->kb);
1226 pkc->cont (pkc->cont_cls,
1229 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1233 keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
1234 /* first character of keyword indicates if it is
1235 mandatory or not -- ignore for hashing */
1236 GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
1237 GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
1238 GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1],
1239 pkc->slen + pkc->mdsize,
1243 pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
1244 GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace);
1245 GNUNET_CRYPTO_hash (&pkc->cpy->keyspace,
1246 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1248 GNUNET_assert (GNUNET_OK ==
1249 GNUNET_CRYPTO_rsa_sign (pk,
1251 &pkc->cpy->signature));
1252 GNUNET_CRYPTO_rsa_key_free (pk);
1253 GNUNET_DATASTORE_put (pkc->dsh,
1257 sizeof (struct KBlock) +
1260 GNUNET_DATASTORE_BLOCKTYPE_KBLOCK,
1263 pkc->expirationTime,
1264 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1271 * Publish a CHK under various keywords on GNUnet.
1273 * @param h handle to the file sharing subsystem
1274 * @param ksk_uri keywords to use
1275 * @param meta metadata to use
1276 * @param uri URI to refer to in the KBlock
1277 * @param expirationTime when the KBlock expires
1278 * @param anonymity anonymity level for the KBlock
1279 * @param priority priority for the KBlock
1280 * @param options publication options
1281 * @param cont continuation
1282 * @param cont_cls closure for cont
1285 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
1286 struct GNUNET_FS_Uri *ksk_uri,
1287 struct GNUNET_CONTAINER_MetaData *meta,
1288 struct GNUNET_FS_Uri *uri,
1289 struct GNUNET_TIME_Absolute expirationTime,
1292 enum GNUNET_FS_PublishOptions options,
1293 GNUNET_FS_PublishContinuation cont,
1296 struct PublishKskContext *pkc;
1301 pkc = GNUNET_malloc (sizeof (struct PublishKskContext));
1303 pkc->expirationTime = expirationTime;
1304 pkc->anonymity = anonymity;
1305 pkc->priority = priority;
1307 pkc->cont_cls = cont_cls;
1308 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1310 pkc->dsh = GNUNET_DATASTORE_connect (h->cfg,
1312 if (pkc->dsh == NULL)
1314 cont (cont_cls, NULL, _("Could not connect to datastore."));
1319 pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1320 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1321 GNUNET_assert (pkc->mdsize >= 0);
1322 uris = GNUNET_FS_uri_to_string (uri);
1323 pkc->slen = strlen (uris) + 1;
1324 size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen;
1325 if (size > MAX_KBLOCK_SIZE)
1327 size = MAX_KBLOCK_SIZE;
1328 pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen;
1330 pkc->kb = GNUNET_malloc (size);
1331 kbe = (char *) &pkc->kb[1];
1332 memcpy (kbe, uris, pkc->slen);
1334 pkc->mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1337 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1338 if (pkc->mdsize == -1)
1342 GNUNET_free (pkc->kb);
1343 if (pkc->dsh != NULL)
1344 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1345 cont (cont_cls, NULL, _("Internal error."));
1349 size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize;
1351 pkc->cpy = GNUNET_malloc (size);
1352 pkc->cpy->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
1353 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
1356 pkc->cpy->purpose.purpose = htonl(GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK);
1357 pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
1358 GNUNET_SCHEDULER_add_continuation (h->sched,
1362 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1367 * Context for the SKS publication.
1369 struct PublishSksContext
1373 * Global FS context.
1375 struct GNUNET_FS_Uri *uri;
1378 * Handle to the datastore.
1380 struct GNUNET_DATASTORE_Handle *dsh;
1383 * Function to call once we're done.
1385 GNUNET_FS_PublishContinuation cont;
1396 * Function called by the datastore API with
1397 * the result from the PUT (SBlock) request.
1399 * @param cls closure of type "struct PublishSksContext*"
1400 * @param success GNUNET_OK on success
1401 * @param msg error message (or NULL)
1404 sb_put_cont (void *cls,
1408 struct PublishSksContext *psc = cls;
1410 if (NULL != psc->dsh)
1411 GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
1412 if (GNUNET_OK != success)
1413 psc->cont (psc->cont_cls,
1417 psc->cont (psc->cont_cls,
1420 GNUNET_FS_uri_destroy (psc->uri);
1426 * Publish an SBlock on GNUnet.
1428 * @param h handle to the file sharing subsystem
1429 * @param namespace namespace to publish in
1430 * @param identifier identifier to use
1431 * @param update update identifier to use
1432 * @param meta metadata to use
1433 * @param uri URI to refer to in the SBlock
1434 * @param expirationTime when the SBlock expires
1435 * @param anonymity anonymity level for the SBlock
1436 * @param priority priority for the SBlock
1437 * @param options publication options
1438 * @param cont continuation
1439 * @param cont_cls closure for cont
1442 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
1443 struct GNUNET_FS_Namespace *namespace,
1444 const char *identifier,
1446 struct GNUNET_CONTAINER_MetaData *meta,
1447 struct GNUNET_FS_Uri *uri,
1448 struct GNUNET_TIME_Absolute expirationTime,
1451 enum GNUNET_FS_PublishOptions options,
1452 GNUNET_FS_PublishContinuation cont,
1455 struct PublishSksContext *psc;
1456 struct GNUNET_CRYPTO_AesSessionKey sk;
1457 struct GNUNET_CRYPTO_AesInitializationVector iv;
1458 struct GNUNET_FS_Uri *sks_uri;
1466 struct SBlock *sb_enc;
1468 GNUNET_HashCode key; /* hash of thisId = key */
1469 GNUNET_HashCode id; /* hash of hc = identifier */
1471 uris = GNUNET_FS_uri_to_string (uri);
1472 slen = strlen (uris) + 1;
1473 idlen = strlen (identifier);
1476 nidlen = strlen (update) + 1;
1477 mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1478 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1480 size = sizeof (struct SBlock) + slen + nidlen + mdsize;
1481 if (size > MAX_SBLOCK_SIZE)
1483 size = MAX_SBLOCK_SIZE;
1484 mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
1486 sb = GNUNET_malloc (sizeof (struct SBlock) + size);
1487 dest = (char *) &sb[1];
1488 memcpy (dest, update, nidlen);
1490 memcpy (dest, uris, slen);
1492 mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1495 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1503 _("Internal error."));
1506 size = sizeof (struct SBlock) + mdsize + slen + nidlen;
1507 sb_enc = GNUNET_malloc (sizeof (struct SBlock) + size);
1508 GNUNET_CRYPTO_hash (identifier, idlen, &key);
1509 GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
1510 sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
1511 sks_uri->type = sks;
1512 GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
1513 GNUNET_CRYPTO_hash (&sb_enc->subspace,
1514 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1515 &sks_uri->data.sks.namespace);
1516 sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
1517 GNUNET_CRYPTO_hash_xor (&id,
1518 &sks_uri->data.sks.namespace,
1519 &sb_enc->identifier);
1520 GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
1521 GNUNET_CRYPTO_aes_encrypt (&sb[1],
1522 size - sizeof (struct SBlock),
1527 sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
1528 sb_enc->purpose.size = htonl(slen + mdsize + nidlen
1529 + sizeof(struct SBlock)
1530 - sizeof(struct GNUNET_CRYPTO_RsaSignature));
1531 GNUNET_assert (GNUNET_OK ==
1532 GNUNET_CRYPTO_rsa_sign (namespace->key,
1534 &sb_enc->signature));
1535 psc = GNUNET_malloc (sizeof(struct PublishSksContext));
1538 psc->cont_cls = cont_cls;
1539 if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1541 GNUNET_free (sb_enc);
1547 psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
1548 if (NULL == psc->dsh)
1550 GNUNET_free (sb_enc);
1553 _("Failed to connect to datastore."));
1557 GNUNET_DATASTORE_put (psc->dsh,
1562 GNUNET_DATASTORE_BLOCKTYPE_SBLOCK,
1566 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1569 GNUNET_free (sb_enc);
1573 /* end of fs_publish.c */