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