2 This file is part of GNUnet.
3 Copyright (C) 2003--2013, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file fs/fs_unindex.c
21 * @author Krista Grothoff
22 * @author Christian Grothoff
23 * @brief Unindex file.
26 #include "gnunet_constants.h"
27 #include "gnunet_fs_service.h"
28 #include "gnunet_protocols.h"
32 #include "fs_publish_ublock.h"
36 * Function called by the tree encoder to obtain
37 * a block of plaintext data (for the lowest level
40 * @param cls our publishing context
41 * @param offset identifies which block to get
42 * @param max (maximum) number of bytes to get; returning
43 * fewer will also cause errors
44 * @param buf where to copy the plaintext buffer
45 * @param emsg location to store an error message (on error)
46 * @return number of bytes copied to buf, 0 on error
49 unindex_reader (void *cls,
55 struct GNUNET_FS_UnindexContext *uc = cls;
58 pt_size = GNUNET_MIN (max, uc->file_size - offset);
59 if (offset != GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET))
61 *emsg = GNUNET_strdup (_("Failed to find given position in file"));
64 if (pt_size != GNUNET_DISK_file_read (uc->fh, buf, pt_size))
66 *emsg = GNUNET_strdup (_("Failed to read file"));
74 * Fill in all of the generic fields for
75 * an unindex event and call the callback.
77 * @param pi structure to fill in
78 * @param uc overall unindex context
79 * @param offset where we are in the file (for progress)
82 GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
83 struct GNUNET_FS_UnindexContext *uc,
86 pi->value.unindex.uc = uc;
87 pi->value.unindex.cctx = uc->client_info;
88 pi->value.unindex.filename = uc->filename;
89 pi->value.unindex.size = uc->file_size;
90 pi->value.unindex.eta =
91 GNUNET_TIME_calculate_eta (uc->start_time, offset, uc->file_size);
92 pi->value.unindex.duration =
93 GNUNET_TIME_absolute_get_duration (uc->start_time);
94 pi->value.unindex.completed = offset;
96 uc->client_info = uc->h->upcb (uc->h->upcb_cls, pi);
101 * Function called with information about our
102 * progress in computing the tree encoding.
105 * @param offset where are we in the file
106 * @param pt_block plaintext of the currently processed block
107 * @param pt_size size of pt_block
108 * @param depth depth of the block in the tree, 0 for DBLOCK
111 unindex_progress (void *cls,
113 const void *pt_block,
117 struct GNUNET_FS_UnindexContext *uc = cls;
118 struct GNUNET_FS_ProgressInfo pi;
120 pi.status = GNUNET_FS_STATUS_UNINDEX_PROGRESS;
121 pi.value.unindex.specifics.progress.data = pt_block;
122 pi.value.unindex.specifics.progress.offset = offset;
123 pi.value.unindex.specifics.progress.data_len = pt_size;
124 pi.value.unindex.specifics.progress.depth = depth;
125 GNUNET_FS_unindex_make_status_ (&pi, uc, offset);
130 * We've encountered an error during
131 * unindexing. Signal the client.
133 * @param uc context for the failed unindexing operation
136 signal_unindex_error (struct GNUNET_FS_UnindexContext *uc)
138 struct GNUNET_FS_ProgressInfo pi;
140 pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR;
141 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
142 pi.value.unindex.specifics.error.message = uc->emsg;
143 GNUNET_FS_unindex_make_status_ (&pi, uc, 0);
148 * Continuation called to notify client about result of the
149 * datastore removal operation.
152 * @param success #GNUNET_SYSERR on failure
153 * @param min_expiration minimum expiration time required for content to be stored
154 * @param msg NULL on success, otherwise an error message
157 process_cont (void *cls,
159 struct GNUNET_TIME_Absolute min_expiration,
162 struct GNUNET_FS_UnindexContext *uc = cls;
164 if (success == GNUNET_SYSERR)
166 uc->emsg = GNUNET_strdup (msg);
167 signal_unindex_error (uc);
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171 "Datastore REMOVE operation succeeded\n");
172 GNUNET_FS_tree_encoder_next (uc->tc);
177 * Function called asking for the current (encoded)
178 * block to be processed. After processing the
179 * client should either call "GNUNET_FS_tree_encode_next"
180 * or (on error) "GNUNET_FS_tree_encode_finish".
183 * @param chk content hash key for the block (key for lookup in the datastore)
184 * @param offset offset of the block
185 * @param depth depth of the block, 0 for DBLOCK
186 * @param type type of the block (IBLOCK or DBLOCK)
187 * @param block the (encrypted) block
188 * @param block_size size of block (in bytes)
191 unindex_process (void *cls,
192 const struct ContentHashKey *chk,
195 enum GNUNET_BLOCK_Type type,
199 struct GNUNET_FS_UnindexContext *uc = cls;
202 struct OnDemandBlock odb;
204 if (type != GNUNET_BLOCK_TYPE_FS_DBLOCK)
209 else /* on-demand encoded DBLOCK */
211 size = sizeof (struct OnDemandBlock);
212 odb.offset = GNUNET_htonll (offset);
213 odb.file_id = uc->file_id;
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
217 "Sending REMOVE request to DATASTORE service\n");
218 GNUNET_DATASTORE_remove (uc->dsh, &chk->query, size, data, -2, 1,
225 * Function called with the response from the FS service to our
226 * unindexing request.
228 * @param cls closure, unindex context
229 * @param msg the response
232 handle_unindex_response (void *cls,
233 const struct GNUNET_MessageHeader *msg)
235 struct GNUNET_FS_UnindexContext *uc = cls;
236 struct GNUNET_FS_ProgressInfo pi;
240 GNUNET_MQ_destroy (uc->mq);
243 uc->state = UNINDEX_STATE_COMPLETE;
244 pi.status = GNUNET_FS_STATUS_UNINDEX_COMPLETED;
245 pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
246 GNUNET_FS_unindex_sync_ (uc);
247 GNUNET_FS_unindex_make_status_ (&pi,
254 * Generic error handler, called with the appropriate error code and
255 * the same closure specified at the creation of the message queue.
256 * Not every message queue implementation supports an error handler.
258 * @param cls closure with the `struct GNUNET_FS_UnindexContext *`
259 * @param error error code
262 unindex_mq_error_handler (void *cls,
263 enum GNUNET_MQ_Error error)
265 struct GNUNET_FS_UnindexContext *uc = cls;
269 GNUNET_MQ_destroy (uc->mq);
272 uc->state = UNINDEX_STATE_ERROR;
273 uc->emsg = GNUNET_strdup (_("Error communicating with `fs' service."));
274 GNUNET_FS_unindex_sync_ (uc);
275 signal_unindex_error (uc);
280 * Function called when we are done with removing UBlocks.
281 * Disconnect from datastore and notify FS service about
284 * @param uc our unindexing context
287 unindex_finish (struct GNUNET_FS_UnindexContext *uc)
289 struct GNUNET_MQ_MessageHandler handlers[] = {
290 GNUNET_MQ_hd_fixed_size (unindex_response,
291 GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK,
292 struct GNUNET_MessageHeader,
294 GNUNET_MQ_handler_end ()
297 struct GNUNET_MQ_Envelope *env;
298 struct UnindexMessage *req;
300 /* generate final progress message */
301 unindex_progress (uc,
306 GNUNET_FS_tree_encoder_finish (uc->tc,
309 GNUNET_DISK_file_close (uc->fh);
311 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
313 uc->state = UNINDEX_STATE_FS_NOTIFY;
314 GNUNET_FS_unindex_sync_ (uc);
315 uc->mq = GNUNET_CLIENT_connect (uc->h->cfg,
318 &unindex_mq_error_handler,
322 uc->state = UNINDEX_STATE_ERROR;
324 GNUNET_strdup (_("Failed to connect to FS service for unindexing."));
325 GNUNET_FS_unindex_sync_ (uc);
326 signal_unindex_error (uc);
329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
330 "Sending UNINDEX message to FS service\n");
331 env = GNUNET_MQ_msg (req,
332 GNUNET_MESSAGE_TYPE_FS_UNINDEX);
334 req->file_id = uc->file_id;
335 GNUNET_MQ_send (uc->mq,
341 * Function called by the directory scanner as we extract keywords
342 * that we will need to remove UBlocks.
344 * @param cls the 'struct GNUNET_FS_UnindexContext *'
345 * @param filename which file we are making progress on
346 * @param is_directory #GNUNET_YES if this is a directory,
347 * #GNUNET_NO if this is a file
348 * #GNUNET_SYSERR if it is neither (or unknown)
349 * @param reason kind of progress we are making
352 unindex_directory_scan_cb (void *cls,
353 const char *filename,
355 enum GNUNET_FS_DirScannerProgressUpdateReason reason)
357 struct GNUNET_FS_UnindexContext *uc = cls;
358 static struct GNUNET_FS_ShareTreeItem * directory_scan_result;
362 case GNUNET_FS_DIRSCANNER_FINISHED:
363 directory_scan_result = GNUNET_FS_directory_scan_get_result (uc->dscan);
365 if (NULL != directory_scan_result->ksk_uri)
367 uc->ksk_uri = GNUNET_FS_uri_dup (directory_scan_result->ksk_uri);
368 uc->state = UNINDEX_STATE_DS_REMOVE_KBLOCKS;
369 GNUNET_FS_unindex_sync_ (uc);
370 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
374 uc->emsg = GNUNET_strdup (_("Failed to get KSKs from directory scan."));
375 GNUNET_FS_unindex_sync_ (uc);
378 GNUNET_FS_share_tree_free (directory_scan_result);
380 case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
381 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
382 _("Internal error scanning `%s'.\n"),
384 GNUNET_FS_directory_scan_abort (uc->dscan);
386 uc->emsg = GNUNET_strdup (_("Failed to get KSKs from directory scan."));
387 GNUNET_FS_unindex_sync_ (uc);
397 * If necessary, connect to the datastore and remove the UBlocks.
399 * @param uc context for the unindex operation.
402 GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc)
407 GNUNET_CONFIGURATION_get_value_string (uc->h->cfg, "FS", "EXTRACTORS", &ex))
409 uc->dscan = GNUNET_FS_directory_scan_start (uc->filename,
411 &unindex_directory_scan_cb,
413 GNUNET_free_non_null (ex);
418 * Continuation called to notify client about result of the remove
419 * operation for the UBlock.
421 * @param cls the 'struct GNUNET_FS_UnindexContext *'
422 * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
423 * GNUNET_NO if content was already there
424 * GNUNET_YES (or other positive value) on success
425 * @param min_expiration minimum expiration time required for 0-priority content to be stored
426 * by the datacache at this time, zero for unknown, forever if we have no
427 * space for 0-priority content
428 * @param msg NULL on success, otherwise an error message
431 continue_after_remove (void *cls,
433 struct GNUNET_TIME_Absolute min_expiration,
436 struct GNUNET_FS_UnindexContext *uc = cls;
439 if (success != GNUNET_YES)
440 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
441 _("Failed to remove UBlock: %s\n"),
444 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
449 * Function called from datastore with result from us looking for
450 * a UBlock. There are four cases:
451 * 1) no result, means we move on to the next keyword
452 * 2) data hash is the same as an already seen data hash, means we move on to
454 * 3) UBlock for a different CHK, means we keep looking for more
455 * 4) UBlock is for our CHK, means we remove the block and then move
456 * on to the next keyword
458 * @param cls the 'struct GNUNET_FS_UnindexContext *'
459 * @param key key for the content
460 * @param size number of bytes in data
461 * @param data content stored
462 * @param type type of the content
463 * @param priority priority of the content
464 * @param anonymity anonymity-level for the content
465 * @param replication replication-level for the content
466 * @param expiration expiration time for the content
467 * @param uid unique identifier for the datum;
468 * maybe 0 if no unique identifier is available
471 process_kblock_for_unindex (void *cls,
472 const struct GNUNET_HashCode *key,
475 enum GNUNET_BLOCK_Type type,
478 uint32_t replication,
479 struct GNUNET_TIME_Absolute expiration,
482 struct GNUNET_FS_UnindexContext *uc = cls;
483 const struct UBlock *ub;
484 struct GNUNET_FS_Uri *chk_uri;
485 struct GNUNET_HashCode query;
492 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
495 GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type);
496 if (size < sizeof (struct UBlock))
502 GNUNET_CRYPTO_hash (&ub->verification_key,
503 sizeof (ub->verification_key),
505 if (0 != memcmp (&query,
507 sizeof (struct GNUNET_HashCode)))
509 /* result does not match our keyword, skip */
513 char pt[size - sizeof (struct UBlock)];
514 struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
517 GNUNET_CRYPTO_ecdsa_key_get_public (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
519 keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
520 GNUNET_FS_ublock_decrypt_ (&ub[1], size - sizeof (struct UBlock),
524 if (NULL == memchr (&pt[1], 0, sizeof (pt) - 1))
526 GNUNET_break_op (0); /* malformed UBlock */
529 chk_uri = GNUNET_FS_uri_parse (&pt[1], NULL);
532 GNUNET_break_op (0); /* malformed UBlock */
536 if (0 != memcmp (&uc->chk,
537 &chk_uri->data.chk.chk,
538 sizeof (struct ContentHashKey)))
540 /* different CHK, ignore */
541 GNUNET_FS_uri_destroy (chk_uri);
544 GNUNET_FS_uri_destroy (chk_uri);
546 uc->dqe = GNUNET_DATASTORE_remove (uc->dsh,
552 &continue_after_remove,
556 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
557 uid + 1 /* next_uid */,
560 GNUNET_BLOCK_TYPE_FS_UBLOCK,
563 &process_kblock_for_unindex,
569 * If necessary, connect to the datastore and remove the KBlocks.
571 * @param uc context for the unindex operation.
574 GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
577 const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon;
578 struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
579 struct GNUNET_CRYPTO_EcdsaPublicKey dpub;
582 uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg);
585 uc->state = UNINDEX_STATE_ERROR;
586 uc->emsg = GNUNET_strdup (_("Failed to connect to `datastore' service."));
587 GNUNET_FS_unindex_sync_ (uc);
588 signal_unindex_error (uc);
591 if ( (NULL == uc->ksk_uri) ||
592 (uc->ksk_offset >= uc->ksk_uri->data.ksk.keywordCount) )
597 anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
598 GNUNET_CRYPTO_ecdsa_key_get_public (anon,
600 keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
601 GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub,
605 GNUNET_CRYPTO_hash (&dpub,
608 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
612 GNUNET_BLOCK_TYPE_FS_UBLOCK,
615 &process_kblock_for_unindex,
621 * Function called when the tree encoder has
622 * processed all blocks. Clean up.
624 * @param cls our unindexing context
627 unindex_extract_keywords (void *cls)
629 struct GNUNET_FS_UnindexContext *uc = cls;
631 uc->state = UNINDEX_STATE_EXTRACT_KEYWORDS;
632 GNUNET_FS_unindex_sync_ (uc);
633 GNUNET_FS_unindex_do_extract_keywords_ (uc);
638 * Connect to the datastore and remove the blocks.
640 * @param uc context for the unindex operation.
643 GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc)
646 uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg);
649 uc->state = UNINDEX_STATE_ERROR;
650 uc->emsg = GNUNET_strdup (_("Failed to connect to `datastore' service."));
651 GNUNET_FS_unindex_sync_ (uc);
652 signal_unindex_error (uc);
656 GNUNET_DISK_file_open (uc->filename, GNUNET_DISK_OPEN_READ,
657 GNUNET_DISK_PERM_NONE);
660 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
662 uc->state = UNINDEX_STATE_ERROR;
663 uc->emsg = GNUNET_strdup (_("Failed to open file for unindexing."));
664 GNUNET_FS_unindex_sync_ (uc);
665 signal_unindex_error (uc);
669 GNUNET_FS_tree_encoder_create (uc->h,
675 &unindex_extract_keywords);
676 GNUNET_FS_tree_encoder_next (uc->tc);
681 * Function called once the hash of the file
682 * that is being unindexed has been computed.
684 * @param cls closure, unindex context
685 * @param file_id computed hash, NULL on error
688 GNUNET_FS_unindex_process_hash_ (void *cls,
689 const struct GNUNET_HashCode *file_id)
691 struct GNUNET_FS_UnindexContext *uc = cls;
694 if (uc->state != UNINDEX_STATE_HASHING)
696 GNUNET_FS_unindex_stop (uc);
701 uc->state = UNINDEX_STATE_ERROR;
702 uc->emsg = GNUNET_strdup (_("Failed to compute hash of file."));
703 GNUNET_FS_unindex_sync_ (uc);
704 signal_unindex_error (uc);
707 uc->file_id = *file_id;
708 uc->state = UNINDEX_STATE_DS_REMOVE;
709 GNUNET_FS_unindex_sync_ (uc);
710 GNUNET_FS_unindex_do_remove_ (uc);
715 * Create SUSPEND event for the given unindex operation
716 * and then clean up our state (without stop signal).
718 * @param cls the `struct GNUNET_FS_UnindexContext` to signal for
721 GNUNET_FS_unindex_signal_suspend_ (void *cls)
723 struct GNUNET_FS_UnindexContext *uc = cls;
724 struct GNUNET_FS_ProgressInfo pi;
726 /* FIXME: lots of duplication with unindex_stop here! */
727 if (uc->dscan != NULL)
729 GNUNET_FS_directory_scan_abort (uc->dscan);
734 GNUNET_DATASTORE_cancel (uc->dqe);
739 GNUNET_CRYPTO_hash_file_cancel (uc->fhc);
742 if (NULL != uc->ksk_uri)
744 GNUNET_FS_uri_destroy (uc->ksk_uri);
749 GNUNET_MQ_destroy (uc->mq);
754 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
759 GNUNET_FS_tree_encoder_finish (uc->tc, NULL);
764 GNUNET_DISK_file_close (uc->fh);
767 GNUNET_FS_end_top (uc->h, uc->top);
768 pi.status = GNUNET_FS_STATUS_UNINDEX_SUSPEND;
769 GNUNET_FS_unindex_make_status_ (&pi, uc,
771 UNINDEX_STATE_COMPLETE) ? uc->file_size : 0);
772 GNUNET_break (NULL == uc->client_info);
773 GNUNET_free (uc->filename);
774 GNUNET_free_non_null (uc->serialization);
775 GNUNET_free_non_null (uc->emsg);
783 * @param h handle to the file sharing subsystem
784 * @param filename file to unindex
785 * @param cctx initial value for the client context
786 * @return NULL on error, otherwise handle
788 struct GNUNET_FS_UnindexContext *
789 GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
790 const char *filename,
793 struct GNUNET_FS_UnindexContext *uc;
794 struct GNUNET_FS_ProgressInfo pi;
798 GNUNET_DISK_file_size (filename,
803 uc = GNUNET_new (struct GNUNET_FS_UnindexContext);
805 uc->filename = GNUNET_strdup (filename);
806 uc->start_time = GNUNET_TIME_absolute_get ();
807 uc->file_size = size;
808 uc->client_info = cctx;
809 GNUNET_FS_unindex_sync_ (uc);
810 pi.status = GNUNET_FS_STATUS_UNINDEX_START;
811 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
812 GNUNET_FS_unindex_make_status_ (&pi, uc, 0);
814 GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
817 &GNUNET_FS_unindex_process_hash_, uc);
818 uc->top = GNUNET_FS_make_top (h,
819 &GNUNET_FS_unindex_signal_suspend_,
826 * Clean up after completion of an unindex operation.
831 GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
833 struct GNUNET_FS_ProgressInfo pi;
835 if (NULL != uc->dscan)
837 GNUNET_FS_directory_scan_abort (uc->dscan);
842 GNUNET_DATASTORE_cancel (uc->dqe);
847 GNUNET_CRYPTO_hash_file_cancel (uc->fhc);
852 GNUNET_MQ_destroy (uc->mq);
857 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
860 if (NULL != uc->ksk_uri)
862 GNUNET_FS_uri_destroy (uc->ksk_uri);
867 GNUNET_FS_tree_encoder_finish (uc->tc, NULL);
872 GNUNET_DISK_file_close (uc->fh);
875 GNUNET_FS_end_top (uc->h, uc->top);
876 if (uc->serialization != NULL)
878 GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
880 GNUNET_free (uc->serialization);
881 uc->serialization = NULL;
883 pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED;
884 pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
885 GNUNET_FS_unindex_make_status_ (&pi, uc,
887 UNINDEX_STATE_COMPLETE) ? uc->file_size : 0);
888 GNUNET_break (NULL == uc->client_info);
889 GNUNET_free_non_null (uc->emsg);
890 GNUNET_free (uc->filename);
894 /* end of fs_unindex.c */