diff options
Diffstat (limited to 'src/fs/fs_unindex.c')
-rw-r--r-- | src/fs/fs_unindex.c | 901 |
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 | */ | ||
50 | static size_t | ||
51 | unindex_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 | */ | ||
83 | void | ||
84 | GNUNET_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 | */ | ||
112 | static void | ||
113 | unindex_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 | */ | ||
137 | static void | ||
138 | signal_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 | */ | ||
158 | static void | ||
159 | process_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 | */ | ||
192 | static void | ||
193 | unindex_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 | */ | ||
233 | static void | ||
234 | handle_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 | */ | ||
263 | static void | ||
264 | unindex_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 | */ | ||
288 | static void | ||
289 | unindex_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 | */ | ||
353 | static void | ||
354 | unindex_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 | */ | ||
405 | void | ||
406 | GNUNET_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 | */ | ||
435 | static void | ||
436 | continue_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 | */ | ||
475 | static void | ||
476 | process_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; | ||
561 | get_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 | */ | ||
579 | void | ||
580 | GNUNET_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 | */ | ||
632 | static void | ||
633 | unindex_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 | */ | ||
648 | void | ||
649 | GNUNET_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 | */ | ||
693 | void | ||
694 | GNUNET_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 | */ | ||
726 | void | ||
727 | GNUNET_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 | */ | ||
794 | struct GNUNET_FS_UnindexContext * | ||
795 | GNUNET_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 | */ | ||
836 | void | ||
837 | GNUNET_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 */ | ||