aboutsummaryrefslogtreecommitdiff
path: root/src/service/fs/fs_unindex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/fs/fs_unindex.c')
-rw-r--r--src/service/fs/fs_unindex.c902
1 files changed, 902 insertions, 0 deletions
diff --git a/src/service/fs/fs_unindex.c b/src/service/fs/fs_unindex.c
new file mode 100644
index 000000000..68ba667c4
--- /dev/null
+++ b/src/service/fs/fs_unindex.c
@@ -0,0 +1,902 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2003--2013, 2016 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file fs/fs_unindex.c
23 * @author Krista Grothoff
24 * @author Christian Grothoff
25 * @brief Unindex file.
26 */
27#include "platform.h"
28#include "gnunet_constants.h"
29
30#include "gnunet_fs_service.h"
31#include "gnunet_protocols.h"
32#include "fs_api.h"
33#include "fs_tree.h"
34#include "block_fs.h"
35#include "fs_publish_ublock.h"
36
37
38/**
39 * Function called by the tree encoder to obtain
40 * a block of plaintext data (for the lowest level
41 * of the tree).
42 *
43 * @param cls our publishing context
44 * @param offset identifies which block to get
45 * @param max (maximum) number of bytes to get; returning
46 * fewer will also cause errors
47 * @param buf where to copy the plaintext buffer
48 * @param emsg location to store an error message (on error)
49 * @return number of bytes copied to buf, 0 on error
50 */
51static size_t
52unindex_reader (void *cls,
53 uint64_t offset,
54 size_t max,
55 void *buf,
56 char **emsg)
57{
58 struct GNUNET_FS_UnindexContext *uc = cls;
59 size_t pt_size;
60
61 pt_size = GNUNET_MIN (max, uc->file_size - offset);
62 if (offset != GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET))
63 {
64 *emsg = GNUNET_strdup (_ ("Failed to find given position in file"));
65 return 0;
66 }
67 if (pt_size != GNUNET_DISK_file_read (uc->fh, buf, pt_size))
68 {
69 *emsg = GNUNET_strdup (_ ("Failed to read file"));
70 return 0;
71 }
72 return pt_size;
73}
74
75
76/**
77 * Fill in all of the generic fields for
78 * an unindex event and call the callback.
79 *
80 * @param pi structure to fill in
81 * @param uc overall unindex context
82 * @param offset where we are in the file (for progress)
83 */
84void
85GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
86 struct GNUNET_FS_UnindexContext *uc,
87 uint64_t offset)
88{
89 pi->value.unindex.uc = uc;
90 pi->value.unindex.cctx = uc->client_info;
91 pi->value.unindex.filename = uc->filename;
92 pi->value.unindex.size = uc->file_size;
93 pi->value.unindex.eta =
94 GNUNET_TIME_calculate_eta (uc->start_time, offset, uc->file_size);
95 pi->value.unindex.duration =
96 GNUNET_TIME_absolute_get_duration (uc->start_time);
97 pi->value.unindex.completed = offset;
98 pi->fsh = uc->h;
99 uc->client_info = uc->h->upcb (uc->h->upcb_cls, pi);
100}
101
102
103/**
104 * Function called with information about our
105 * progress in computing the tree encoding.
106 *
107 * @param cls closure
108 * @param offset where are we in the file
109 * @param pt_block plaintext of the currently processed block
110 * @param pt_size size of pt_block
111 * @param depth depth of the block in the tree, 0 for DBLOCK
112 */
113static void
114unindex_progress (void *cls,
115 uint64_t offset,
116 const void *pt_block,
117 size_t pt_size,
118 unsigned int depth)
119{
120 struct GNUNET_FS_UnindexContext *uc = cls;
121 struct GNUNET_FS_ProgressInfo pi;
122
123 pi.status = GNUNET_FS_STATUS_UNINDEX_PROGRESS;
124 pi.value.unindex.specifics.progress.data = pt_block;
125 pi.value.unindex.specifics.progress.offset = offset;
126 pi.value.unindex.specifics.progress.data_len = pt_size;
127 pi.value.unindex.specifics.progress.depth = depth;
128 GNUNET_FS_unindex_make_status_ (&pi, uc, offset);
129}
130
131
132/**
133 * We've encountered an error during
134 * unindexing. Signal the client.
135 *
136 * @param uc context for the failed unindexing operation
137 */
138static void
139signal_unindex_error (struct GNUNET_FS_UnindexContext *uc)
140{
141 struct GNUNET_FS_ProgressInfo pi;
142
143 pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR;
144 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
145 pi.value.unindex.specifics.error.message = uc->emsg;
146 GNUNET_FS_unindex_make_status_ (&pi, uc, 0);
147}
148
149
150/**
151 * Continuation called to notify client about result of the
152 * datastore removal operation.
153 *
154 * @param cls closure
155 * @param success #GNUNET_SYSERR on failure
156 * @param min_expiration minimum expiration time required for content to be stored
157 * @param msg NULL on success, otherwise an error message
158 */
159static void
160process_cont (void *cls,
161 int success,
162 struct GNUNET_TIME_Absolute min_expiration,
163 const char *msg)
164{
165 struct GNUNET_FS_UnindexContext *uc = cls;
166
167 if (success == GNUNET_SYSERR)
168 {
169 uc->emsg = GNUNET_strdup (msg);
170 signal_unindex_error (uc);
171 return;
172 }
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174 "Datastore REMOVE operation succeeded\n");
175 GNUNET_FS_tree_encoder_next (uc->tc);
176}
177
178
179/**
180 * Function called asking for the current (encoded)
181 * block to be processed. After processing the
182 * client should either call "GNUNET_FS_tree_encode_next"
183 * or (on error) "GNUNET_FS_tree_encode_finish".
184 *
185 * @param cls closure
186 * @param chk content hash key for the block (key for lookup in the datastore)
187 * @param offset offset of the block
188 * @param depth depth of the block, 0 for DBLOCK
189 * @param type type of the block (IBLOCK or DBLOCK)
190 * @param block the (encrypted) block
191 * @param block_size size of block (in bytes)
192 */
193static void
194unindex_process (void *cls,
195 const struct ContentHashKey *chk,
196 uint64_t offset,
197 unsigned int depth,
198 enum GNUNET_BLOCK_Type type,
199 const void *block,
200 uint16_t block_size)
201{
202 struct GNUNET_FS_UnindexContext *uc = cls;
203 uint32_t size;
204 const void *data;
205 struct OnDemandBlock odb;
206
207 if (type != GNUNET_BLOCK_TYPE_FS_DBLOCK)
208 {
209 size = block_size;
210 data = block;
211 }
212 else /* on-demand encoded DBLOCK */
213 {
214 size = sizeof(struct OnDemandBlock);
215 odb.offset = GNUNET_htonll (offset);
216 odb.file_id = uc->file_id;
217 data = &odb;
218 }
219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
220 "Sending REMOVE request to DATASTORE service\n");
221 GNUNET_DATASTORE_remove (uc->dsh, &chk->query, size, data, -2, 1,
222 &process_cont, uc);
223 uc->chk = *chk;
224}
225
226
227/**
228 * Function called with the response from the FS service to our
229 * unindexing request.
230 *
231 * @param cls closure, unindex context
232 * @param msg the response
233 */
234static void
235handle_unindex_response (void *cls,
236 const struct GNUNET_MessageHeader *msg)
237{
238 struct GNUNET_FS_UnindexContext *uc = cls;
239 struct GNUNET_FS_ProgressInfo pi;
240
241 if (NULL != uc->mq)
242 {
243 GNUNET_MQ_destroy (uc->mq);
244 uc->mq = NULL;
245 }
246 uc->state = UNINDEX_STATE_COMPLETE;
247 pi.status = GNUNET_FS_STATUS_UNINDEX_COMPLETED;
248 pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
249 GNUNET_FS_unindex_sync_ (uc);
250 GNUNET_FS_unindex_make_status_ (&pi,
251 uc,
252 uc->file_size);
253}
254
255
256/**
257 * Generic error handler, called with the appropriate error code and
258 * the same closure specified at the creation of the message queue.
259 * Not every message queue implementation supports an error handler.
260 *
261 * @param cls closure with the `struct GNUNET_FS_UnindexContext *`
262 * @param error error code
263 */
264static void
265unindex_mq_error_handler (void *cls,
266 enum GNUNET_MQ_Error error)
267{
268 struct GNUNET_FS_UnindexContext *uc = cls;
269
270 if (NULL != uc->mq)
271 {
272 GNUNET_MQ_destroy (uc->mq);
273 uc->mq = NULL;
274 }
275 uc->state = UNINDEX_STATE_ERROR;
276 uc->emsg = GNUNET_strdup (_ ("Error communicating with `fs' service."));
277 GNUNET_FS_unindex_sync_ (uc);
278 signal_unindex_error (uc);
279}
280
281
282/**
283 * Function called when we are done with removing UBlocks.
284 * Disconnect from datastore and notify FS service about
285 * the unindex event.
286 *
287 * @param uc our unindexing context
288 */
289static void
290unindex_finish (struct GNUNET_FS_UnindexContext *uc)
291{
292 struct GNUNET_MQ_MessageHandler handlers[] = {
293 GNUNET_MQ_hd_fixed_size (unindex_response,
294 GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK,
295 struct GNUNET_MessageHeader,
296 uc),
297 GNUNET_MQ_handler_end ()
298 };
299 char *emsg;
300 struct GNUNET_MQ_Envelope *env;
301 struct UnindexMessage *req;
302
303 /* generate final progress message */
304 unindex_progress (uc,
305 uc->file_size,
306 NULL,
307 0,
308 0);
309 GNUNET_FS_tree_encoder_finish (uc->tc,
310 &emsg);
311 uc->tc = NULL;
312 GNUNET_DISK_file_close (uc->fh);
313 uc->fh = NULL;
314 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
315 uc->dsh = NULL;
316 uc->state = UNINDEX_STATE_FS_NOTIFY;
317 GNUNET_FS_unindex_sync_ (uc);
318 uc->mq = GNUNET_CLIENT_connect (uc->h->cfg,
319 "fs",
320 handlers,
321 &unindex_mq_error_handler,
322 uc);
323 if (NULL == uc->mq)
324 {
325 uc->state = UNINDEX_STATE_ERROR;
326 uc->emsg =
327 GNUNET_strdup (_ ("Failed to connect to FS service for unindexing."));
328 GNUNET_FS_unindex_sync_ (uc);
329 signal_unindex_error (uc);
330 return;
331 }
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Sending UNINDEX message to FS service\n");
334 env = GNUNET_MQ_msg (req,
335 GNUNET_MESSAGE_TYPE_FS_UNINDEX);
336 req->reserved = 0;
337 req->file_id = uc->file_id;
338 GNUNET_MQ_send (uc->mq,
339 env);
340}
341
342
343/**
344 * Function called by the directory scanner as we extract keywords
345 * that we will need to remove UBlocks.
346 *
347 * @param cls the 'struct GNUNET_FS_UnindexContext *'
348 * @param filename which file we are making progress on
349 * @param is_directory #GNUNET_YES if this is a directory,
350 * #GNUNET_NO if this is a file
351 * #GNUNET_SYSERR if it is neither (or unknown)
352 * @param reason kind of progress we are making
353 */
354static void
355unindex_directory_scan_cb (void *cls,
356 const char *filename,
357 int is_directory,
358 enum GNUNET_FS_DirScannerProgressUpdateReason reason)
359{
360 struct GNUNET_FS_UnindexContext *uc = cls;
361 static struct GNUNET_FS_ShareTreeItem *directory_scan_result;
362
363 switch (reason)
364 {
365 case GNUNET_FS_DIRSCANNER_FINISHED:
366 directory_scan_result = GNUNET_FS_directory_scan_get_result (uc->dscan);
367 uc->dscan = NULL;
368 if (NULL != directory_scan_result->ksk_uri)
369 {
370 uc->ksk_uri = GNUNET_FS_uri_dup (directory_scan_result->ksk_uri);
371 uc->state = UNINDEX_STATE_DS_REMOVE_KBLOCKS;
372 GNUNET_FS_unindex_sync_ (uc);
373 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
374 }
375 else
376 {
377 uc->emsg = GNUNET_strdup (_ ("Failed to get KSKs from directory scan."));
378 GNUNET_FS_unindex_sync_ (uc);
379 unindex_finish (uc);
380 }
381 GNUNET_FS_share_tree_free (directory_scan_result);
382 break;
383
384 case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
385 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
386 _ ("Internal error scanning `%s'.\n"),
387 uc->filename);
388 GNUNET_FS_directory_scan_abort (uc->dscan);
389 uc->dscan = NULL;
390 uc->emsg = GNUNET_strdup (_ ("Failed to get KSKs from directory scan."));
391 GNUNET_FS_unindex_sync_ (uc);
392 unindex_finish (uc);
393 break;
394
395 default:
396 break;
397 }
398}
399
400
401/**
402 * If necessary, connect to the datastore and remove the UBlocks.
403 *
404 * @param uc context for the unindex operation.
405 */
406void
407GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc)
408{
409 char *ex;
410
411 if (GNUNET_OK !=
412 GNUNET_CONFIGURATION_get_value_string (uc->h->cfg, "FS", "EXTRACTORS",
413 &ex))
414 ex = NULL;
415 uc->dscan = GNUNET_FS_directory_scan_start (uc->filename,
416 GNUNET_NO, ex,
417 &unindex_directory_scan_cb,
418 uc);
419 GNUNET_free (ex);
420}
421
422
423/**
424 * Continuation called to notify client about result of the remove
425 * operation for the UBlock.
426 *
427 * @param cls the 'struct GNUNET_FS_UnindexContext *'
428 * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
429 * GNUNET_NO if content was already there
430 * GNUNET_YES (or other positive value) on success
431 * @param min_expiration minimum expiration time required for 0-priority content to be stored
432 * by the datacache at this time, zero for unknown, forever if we have no
433 * space for 0-priority content
434 * @param msg NULL on success, otherwise an error message
435 */
436static void
437continue_after_remove (void *cls,
438 int32_t success,
439 struct GNUNET_TIME_Absolute min_expiration,
440 const char *msg)
441{
442 struct GNUNET_FS_UnindexContext *uc = cls;
443
444 uc->dqe = NULL;
445 if (success != GNUNET_YES)
446 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
447 _ ("Failed to remove UBlock: %s\n"),
448 msg);
449 uc->ksk_offset++;
450 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
451}
452
453
454/**
455 * Function called from datastore with result from us looking for
456 * a UBlock. There are four cases:
457 * 1) no result, means we move on to the next keyword
458 * 2) data hash is the same as an already seen data hash, means we move on to
459 * next keyword
460 * 3) UBlock for a different CHK, means we keep looking for more
461 * 4) UBlock is for our CHK, means we remove the block and then move
462 * on to the next keyword
463 *
464 * @param cls the 'struct GNUNET_FS_UnindexContext *'
465 * @param key key for the content
466 * @param size number of bytes in data
467 * @param data content stored
468 * @param type type of the content
469 * @param priority priority of the content
470 * @param anonymity anonymity-level for the content
471 * @param replication replication-level for the content
472 * @param expiration expiration time for the content
473 * @param uid unique identifier for the datum;
474 * maybe 0 if no unique identifier is available
475 */
476static void
477process_kblock_for_unindex (void *cls,
478 const struct GNUNET_HashCode *key,
479 size_t size,
480 const void *data,
481 enum GNUNET_BLOCK_Type type,
482 uint32_t priority,
483 uint32_t anonymity,
484 uint32_t replication,
485 struct GNUNET_TIME_Absolute expiration,
486 uint64_t uid)
487{
488 struct GNUNET_FS_UnindexContext *uc = cls;
489 const struct UBlock *ub;
490 struct GNUNET_FS_Uri *chk_uri;
491 struct GNUNET_HashCode query;
492
493 uc->dqe = NULL;
494 if (NULL == data)
495 {
496 /* no result */
497 uc->ksk_offset++;
498 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
499 return;
500 }
501 GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type);
502 if (size < sizeof(struct UBlock))
503 {
504 GNUNET_break (0);
505 goto get_next;
506 }
507 ub = data;
508 GNUNET_CRYPTO_hash (&ub->verification_key,
509 sizeof(ub->verification_key),
510 &query);
511 if (0 != memcmp (&query,
512 key,
513 sizeof(struct GNUNET_HashCode)))
514 {
515 /* result does not match our keyword, skip */
516 goto get_next;
517 }
518 {
519 char pt[size - sizeof(struct UBlock)];
520 struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
521 const char *keyword;
522
523 GNUNET_CRYPTO_ecdsa_key_get_public (
524 GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
525 &anon_pub);
526 keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
527 GNUNET_FS_ublock_decrypt_ (&ub[1], size - sizeof(struct UBlock),
528 &anon_pub,
529 keyword,
530 pt);
531 if (NULL == memchr (&pt[1], 0, sizeof(pt) - 1))
532 {
533 GNUNET_break_op (0); /* malformed UBlock */
534 goto get_next;
535 }
536 chk_uri = GNUNET_FS_uri_parse (&pt[1], NULL);
537 if (NULL == chk_uri)
538 {
539 GNUNET_break_op (0); /* malformed UBlock */
540 goto get_next;
541 }
542 }
543 if (0 != memcmp (&uc->chk,
544 &chk_uri->data.chk.chk,
545 sizeof(struct ContentHashKey)))
546 {
547 /* different CHK, ignore */
548 GNUNET_FS_uri_destroy (chk_uri);
549 goto get_next;
550 }
551 GNUNET_FS_uri_destroy (chk_uri);
552 /* matches! */
553 uc->dqe = GNUNET_DATASTORE_remove (uc->dsh,
554 key,
555 size,
556 data,
557 0 /* priority */,
558 1 /* queue size */,
559 &continue_after_remove,
560 uc);
561 return;
562get_next:
563 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
564 uid + 1 /* next_uid */,
565 false /* random */,
566 &uc->uquery,
567 GNUNET_BLOCK_TYPE_FS_UBLOCK,
568 0 /* priority */,
569 1 /* queue size */,
570 &process_kblock_for_unindex,
571 uc);
572}
573
574
575/**
576 * If necessary, connect to the datastore and remove the KBlocks.
577 *
578 * @param uc context for the unindex operation.
579 */
580void
581GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
582{
583 const char *keyword;
584 const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon;
585 struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
586 struct GNUNET_CRYPTO_EcdsaPublicKey dpub;
587
588 if (NULL == uc->dsh)
589 uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg);
590 if (NULL == uc->dsh)
591 {
592 uc->state = UNINDEX_STATE_ERROR;
593 uc->emsg = GNUNET_strdup (_ ("Failed to connect to `datastore' service."));
594 GNUNET_FS_unindex_sync_ (uc);
595 signal_unindex_error (uc);
596 return;
597 }
598 if ((NULL == uc->ksk_uri) ||
599 (uc->ksk_offset >= uc->ksk_uri->data.ksk.keywordCount))
600 {
601 unindex_finish (uc);
602 return;
603 }
604 anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
605 GNUNET_CRYPTO_ecdsa_key_get_public (anon,
606 &anon_pub);
607 keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
608 GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub,
609 keyword,
610 "fs-ublock",
611 &dpub);
612 GNUNET_CRYPTO_hash (&dpub,
613 sizeof(dpub),
614 &uc->uquery);
615 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
616 0 /* next_uid */,
617 false /* random */,
618 &uc->uquery,
619 GNUNET_BLOCK_TYPE_FS_UBLOCK,
620 0 /* priority */,
621 1 /* queue size */,
622 &process_kblock_for_unindex,
623 uc);
624}
625
626
627/**
628 * Function called when the tree encoder has
629 * processed all blocks. Clean up.
630 *
631 * @param cls our unindexing context
632 */
633static void
634unindex_extract_keywords (void *cls)
635{
636 struct GNUNET_FS_UnindexContext *uc = cls;
637
638 uc->state = UNINDEX_STATE_EXTRACT_KEYWORDS;
639 GNUNET_FS_unindex_sync_ (uc);
640 GNUNET_FS_unindex_do_extract_keywords_ (uc);
641}
642
643
644/**
645 * Connect to the datastore and remove the blocks.
646 *
647 * @param uc context for the unindex operation.
648 */
649void
650GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc)
651{
652 if (NULL == uc->dsh)
653 uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg);
654 if (NULL == uc->dsh)
655 {
656 uc->state = UNINDEX_STATE_ERROR;
657 uc->emsg = GNUNET_strdup (_ ("Failed to connect to `datastore' service."));
658 GNUNET_FS_unindex_sync_ (uc);
659 signal_unindex_error (uc);
660 return;
661 }
662 uc->fh =
663 GNUNET_DISK_file_open (uc->filename, GNUNET_DISK_OPEN_READ,
664 GNUNET_DISK_PERM_NONE);
665 if (NULL == uc->fh)
666 {
667 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
668 uc->dsh = NULL;
669 uc->state = UNINDEX_STATE_ERROR;
670 uc->emsg = GNUNET_strdup (_ ("Failed to open file for unindexing."));
671 GNUNET_FS_unindex_sync_ (uc);
672 signal_unindex_error (uc);
673 return;
674 }
675 uc->tc =
676 GNUNET_FS_tree_encoder_create (uc->h,
677 uc->file_size,
678 uc,
679 &unindex_reader,
680 &unindex_process,
681 &unindex_progress,
682 &unindex_extract_keywords);
683 GNUNET_FS_tree_encoder_next (uc->tc);
684}
685
686
687/**
688 * Function called once the hash of the file
689 * that is being unindexed has been computed.
690 *
691 * @param cls closure, unindex context
692 * @param file_id computed hash, NULL on error
693 */
694void
695GNUNET_FS_unindex_process_hash_ (void *cls,
696 const struct GNUNET_HashCode *file_id)
697{
698 struct GNUNET_FS_UnindexContext *uc = cls;
699
700 uc->fhc = NULL;
701 if (uc->state != UNINDEX_STATE_HASHING)
702 {
703 GNUNET_FS_unindex_stop (uc);
704 return;
705 }
706 if (file_id == NULL)
707 {
708 uc->state = UNINDEX_STATE_ERROR;
709 uc->emsg = GNUNET_strdup (_ ("Failed to compute hash of file."));
710 GNUNET_FS_unindex_sync_ (uc);
711 signal_unindex_error (uc);
712 return;
713 }
714 uc->file_id = *file_id;
715 uc->state = UNINDEX_STATE_DS_REMOVE;
716 GNUNET_FS_unindex_sync_ (uc);
717 GNUNET_FS_unindex_do_remove_ (uc);
718}
719
720
721/**
722 * Create SUSPEND event for the given unindex operation
723 * and then clean up our state (without stop signal).
724 *
725 * @param cls the `struct GNUNET_FS_UnindexContext` to signal for
726 */
727void
728GNUNET_FS_unindex_signal_suspend_ (void *cls)
729{
730 struct GNUNET_FS_UnindexContext *uc = cls;
731 struct GNUNET_FS_ProgressInfo pi;
732
733 /* FIXME: lots of duplication with unindex_stop here! */
734 if (uc->dscan != NULL)
735 {
736 GNUNET_FS_directory_scan_abort (uc->dscan);
737 uc->dscan = NULL;
738 }
739 if (NULL != uc->dqe)
740 {
741 GNUNET_DATASTORE_cancel (uc->dqe);
742 uc->dqe = NULL;
743 }
744 if (uc->fhc != NULL)
745 {
746 GNUNET_CRYPTO_hash_file_cancel (uc->fhc);
747 uc->fhc = NULL;
748 }
749 if (NULL != uc->ksk_uri)
750 {
751 GNUNET_FS_uri_destroy (uc->ksk_uri);
752 uc->ksk_uri = NULL;
753 }
754 if (NULL != uc->mq)
755 {
756 GNUNET_MQ_destroy (uc->mq);
757 uc->mq = NULL;
758 }
759 if (NULL != uc->dsh)
760 {
761 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
762 uc->dsh = NULL;
763 }
764 if (NULL != uc->tc)
765 {
766 GNUNET_FS_tree_encoder_finish (uc->tc, NULL);
767 uc->tc = NULL;
768 }
769 if (uc->fh != NULL)
770 {
771 GNUNET_DISK_file_close (uc->fh);
772 uc->fh = NULL;
773 }
774 GNUNET_FS_end_top (uc->h, uc->top);
775 pi.status = GNUNET_FS_STATUS_UNINDEX_SUSPEND;
776 GNUNET_FS_unindex_make_status_ (&pi, uc,
777 (uc->state ==
778 UNINDEX_STATE_COMPLETE) ? uc->file_size : 0);
779 GNUNET_break (NULL == uc->client_info);
780 GNUNET_free (uc->filename);
781 GNUNET_free (uc->serialization);
782 GNUNET_free (uc->emsg);
783 GNUNET_free (uc);
784}
785
786
787/**
788 * Unindex a file.
789 *
790 * @param h handle to the file sharing subsystem
791 * @param filename file to unindex
792 * @param cctx initial value for the client context
793 * @return NULL on error, otherwise handle
794 */
795struct GNUNET_FS_UnindexContext *
796GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
797 const char *filename,
798 void *cctx)
799{
800 struct GNUNET_FS_UnindexContext *uc;
801 struct GNUNET_FS_ProgressInfo pi;
802 uint64_t size;
803
804 if (GNUNET_OK !=
805 GNUNET_DISK_file_size (filename,
806 &size,
807 GNUNET_YES,
808 GNUNET_YES))
809 return NULL;
810 uc = GNUNET_new (struct GNUNET_FS_UnindexContext);
811 uc->h = h;
812 uc->filename = GNUNET_strdup (filename);
813 uc->start_time = GNUNET_TIME_absolute_get ();
814 uc->file_size = size;
815 uc->client_info = cctx;
816 GNUNET_FS_unindex_sync_ (uc);
817 pi.status = GNUNET_FS_STATUS_UNINDEX_START;
818 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
819 GNUNET_FS_unindex_make_status_ (&pi, uc, 0);
820 uc->fhc =
821 GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
822 filename,
823 HASHING_BLOCKSIZE,
824 &GNUNET_FS_unindex_process_hash_, uc);
825 uc->top = GNUNET_FS_make_top (h,
826 &GNUNET_FS_unindex_signal_suspend_,
827 uc);
828 return uc;
829}
830
831
832/**
833 * Clean up after completion of an unindex operation.
834 *
835 * @param uc handle
836 */
837void
838GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
839{
840 struct GNUNET_FS_ProgressInfo pi;
841
842 if (NULL != uc->dscan)
843 {
844 GNUNET_FS_directory_scan_abort (uc->dscan);
845 uc->dscan = NULL;
846 }
847 if (NULL != uc->dqe)
848 {
849 GNUNET_DATASTORE_cancel (uc->dqe);
850 uc->dqe = NULL;
851 }
852 if (NULL != uc->fhc)
853 {
854 GNUNET_CRYPTO_hash_file_cancel (uc->fhc);
855 uc->fhc = NULL;
856 }
857 if (NULL != uc->mq)
858 {
859 GNUNET_MQ_destroy (uc->mq);
860 uc->mq = NULL;
861 }
862 if (NULL != uc->dsh)
863 {
864 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
865 uc->dsh = NULL;
866 }
867 if (NULL != uc->ksk_uri)
868 {
869 GNUNET_FS_uri_destroy (uc->ksk_uri);
870 uc->ksk_uri = NULL;
871 }
872 if (NULL != uc->tc)
873 {
874 GNUNET_FS_tree_encoder_finish (uc->tc, NULL);
875 uc->tc = NULL;
876 }
877 if (uc->fh != NULL)
878 {
879 GNUNET_DISK_file_close (uc->fh);
880 uc->fh = NULL;
881 }
882 GNUNET_FS_end_top (uc->h, uc->top);
883 if (uc->serialization != NULL)
884 {
885 GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
886 uc->serialization);
887 GNUNET_free (uc->serialization);
888 uc->serialization = NULL;
889 }
890 pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED;
891 pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
892 GNUNET_FS_unindex_make_status_ (&pi, uc,
893 (uc->state ==
894 UNINDEX_STATE_COMPLETE) ? uc->file_size : 0);
895 GNUNET_break (NULL == uc->client_info);
896 GNUNET_free (uc->emsg);
897 GNUNET_free (uc->filename);
898 GNUNET_free (uc);
899}
900
901
902/* end of fs_unindex.c */