diff options
Diffstat (limited to 'src/fs/fs_publish.c')
-rw-r--r-- | src/fs/fs_publish.c | 1624 |
1 files changed, 0 insertions, 1624 deletions
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c deleted file mode 100644 index f891f37a1..000000000 --- a/src/fs/fs_publish.c +++ /dev/null | |||
@@ -1,1624 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010 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 | * @file fs/fs_publish.c | ||
22 | * @brief publish a file or directory in GNUnet | ||
23 | * @see https://gnunet.org/encoding | ||
24 | * @author Krista Bennett | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_signatures.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_fs_service.h" | ||
32 | #include "fs_api.h" | ||
33 | #include "fs_tree.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Fill in all of the generic fields for | ||
38 | * a publish event and call the callback. | ||
39 | * | ||
40 | * @param pi structure to fill in | ||
41 | * @param pc overall publishing context | ||
42 | * @param p file information for the file being published | ||
43 | * @param offset where in the file are we so far | ||
44 | * @return value returned from callback | ||
45 | */ | ||
46 | void * | ||
47 | GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, | ||
48 | struct GNUNET_FS_PublishContext *pc, | ||
49 | const struct GNUNET_FS_FileInformation *p, | ||
50 | uint64_t offset) | ||
51 | { | ||
52 | pi->value.publish.pc = pc; | ||
53 | pi->value.publish.fi = p; | ||
54 | pi->value.publish.cctx = p->client_info; | ||
55 | pi->value.publish.pctx = (NULL == p->dir) ? NULL : p->dir->client_info; | ||
56 | pi->value.publish.filename = p->filename; | ||
57 | pi->value.publish.size = | ||
58 | (GNUNET_YES == p->is_directory) ? p->data.dir.dir_size : | ||
59 | p->data.file.file_size; | ||
60 | pi->value.publish.eta = | ||
61 | GNUNET_TIME_calculate_eta (p->start_time, offset, | ||
62 | pi->value.publish.size); | ||
63 | pi->value.publish.completed = offset; | ||
64 | pi->value.publish.duration = | ||
65 | GNUNET_TIME_absolute_get_duration (p->start_time); | ||
66 | pi->value.publish.anonymity = p->bo.anonymity_level; | ||
67 | pi->fsh = pc->h; | ||
68 | return pc->h->upcb (pc->h->upcb_cls, pi); | ||
69 | } | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Cleanup the publish context, we're done with it. | ||
74 | * | ||
75 | * @param pc struct to clean up | ||
76 | */ | ||
77 | static void | ||
78 | publish_cleanup (struct GNUNET_FS_PublishContext *pc) | ||
79 | { | ||
80 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
81 | "Cleaning up publish context (done!)\n"); | ||
82 | if (NULL != pc->fhc) | ||
83 | { | ||
84 | GNUNET_CRYPTO_hash_file_cancel (pc->fhc); | ||
85 | pc->fhc = NULL; | ||
86 | } | ||
87 | GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); | ||
88 | GNUNET_free (pc->nid); | ||
89 | GNUNET_free (pc->nuid); | ||
90 | GNUNET_free (pc->serialization); | ||
91 | if (NULL != pc->dsh) | ||
92 | { | ||
93 | GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); | ||
94 | pc->dsh = NULL; | ||
95 | } | ||
96 | if (NULL != pc->mq) | ||
97 | { | ||
98 | GNUNET_MQ_destroy (pc->mq); | ||
99 | pc->mq = NULL; | ||
100 | } | ||
101 | GNUNET_assert (NULL == pc->upload_task); | ||
102 | GNUNET_free (pc); | ||
103 | } | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Function called by the datastore API with | ||
108 | * the result from the PUT request. | ||
109 | * | ||
110 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
111 | * @param success #GNUNET_OK on success | ||
112 | * @param min_expiration minimum expiration time required for content to be stored | ||
113 | * @param msg error message (or NULL) | ||
114 | */ | ||
115 | static void | ||
116 | ds_put_cont (void *cls, | ||
117 | int success, | ||
118 | struct GNUNET_TIME_Absolute min_expiration, | ||
119 | const char *msg) | ||
120 | { | ||
121 | struct GNUNET_FS_PublishContext *pc = cls; | ||
122 | struct GNUNET_FS_ProgressInfo pi; | ||
123 | |||
124 | pc->qre = NULL; | ||
125 | if (GNUNET_SYSERR == success) | ||
126 | { | ||
127 | GNUNET_asprintf (&pc->fi_pos->emsg, | ||
128 | _ ("Publishing failed: %s"), | ||
129 | msg); | ||
130 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
131 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
132 | pi.value.publish.specifics.error.message = pc->fi_pos->emsg; | ||
133 | pc->fi_pos->client_info = | ||
134 | GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi_pos, 0); | ||
135 | if ((GNUNET_YES != pc->fi_pos->is_directory) && | ||
136 | (NULL != pc->fi_pos->filename) && | ||
137 | (GNUNET_YES == pc->any_done) && | ||
138 | (GNUNET_YES == pc->fi_pos->data.file.do_index)) | ||
139 | { | ||
140 | /* run unindex to clean up */ | ||
141 | GNUNET_FS_unindex_start (pc->h, | ||
142 | pc->fi_pos->filename, | ||
143 | NULL); | ||
144 | } | ||
145 | return; | ||
146 | } | ||
147 | pc->any_done = GNUNET_YES; | ||
148 | GNUNET_assert (NULL == pc->upload_task); | ||
149 | pc->upload_task = | ||
150 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
151 | &GNUNET_FS_publish_main_, pc); | ||
152 | } | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Generate the callback that signals clients | ||
157 | * that a file (or directory) has been completely | ||
158 | * published. | ||
159 | * | ||
160 | * @param p the completed upload | ||
161 | * @param pc context of the publication | ||
162 | */ | ||
163 | static void | ||
164 | signal_publish_completion (struct GNUNET_FS_FileInformation *p, | ||
165 | struct GNUNET_FS_PublishContext *pc) | ||
166 | { | ||
167 | struct GNUNET_FS_ProgressInfo pi; | ||
168 | |||
169 | pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED; | ||
170 | pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO; | ||
171 | pi.value.publish.specifics.completed.chk_uri = p->chk_uri; | ||
172 | pi.value.publish.specifics.completed.sks_uri = p->sks_uri; | ||
173 | p->client_info = | ||
174 | GNUNET_FS_publish_make_status_ (&pi, pc, p, | ||
175 | p->data.file.file_size); | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Generate the callback that signals clients | ||
181 | * that a file (or directory) has encountered | ||
182 | * a problem during publication. | ||
183 | * | ||
184 | * @param p the upload that had trouble | ||
185 | * @param pc context of the publication | ||
186 | * @param emsg error message | ||
187 | */ | ||
188 | static void | ||
189 | signal_publish_error (struct GNUNET_FS_FileInformation *p, | ||
190 | struct GNUNET_FS_PublishContext *pc, | ||
191 | const char *emsg) | ||
192 | { | ||
193 | struct GNUNET_FS_ProgressInfo pi; | ||
194 | |||
195 | p->emsg = GNUNET_strdup (emsg); | ||
196 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
197 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
198 | pi.value.publish.specifics.error.message = emsg; | ||
199 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
200 | if ((p->is_directory != GNUNET_YES) && | ||
201 | (NULL != p->filename) && | ||
202 | (GNUNET_YES == pc->any_done) && | ||
203 | (p->data.file.do_index == GNUNET_YES)) | ||
204 | { | ||
205 | /* run unindex to clean up */ | ||
206 | GNUNET_FS_unindex_start (pc->h, | ||
207 | p->filename, | ||
208 | NULL); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Datastore returns from reservation cancel request. | ||
215 | * | ||
216 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
217 | * @param success success code (not used) | ||
218 | * @param min_expiration minimum expiration time required for content to be stored | ||
219 | * @param msg error message (typically NULL, not used) | ||
220 | */ | ||
221 | static void | ||
222 | finish_release_reserve (void *cls, int success, | ||
223 | struct GNUNET_TIME_Absolute min_expiration, | ||
224 | const char *msg) | ||
225 | { | ||
226 | struct GNUNET_FS_PublishContext *pc = cls; | ||
227 | |||
228 | pc->qre = NULL; | ||
229 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
230 | "Releasing reserve done!\n"); | ||
231 | signal_publish_completion (pc->fi, pc); | ||
232 | pc->all_done = GNUNET_YES; | ||
233 | GNUNET_FS_publish_sync_ (pc); | ||
234 | } | ||
235 | |||
236 | |||
237 | /** | ||
238 | * We've finished publishing the SBlock as part of a larger upload. | ||
239 | * Check the result and complete the larger upload. | ||
240 | * | ||
241 | * @param cls the `struct GNUNET_FS_PublishContext *` of the larger upload | ||
242 | * @param uri URI of the published SBlock | ||
243 | * @param emsg NULL on success, otherwise error message | ||
244 | */ | ||
245 | static void | ||
246 | publish_sblocks_cont (void *cls, | ||
247 | const struct GNUNET_FS_Uri *uri, | ||
248 | const char *emsg) | ||
249 | { | ||
250 | struct GNUNET_FS_PublishContext *pc = cls; | ||
251 | |||
252 | pc->sks_pc = NULL; | ||
253 | if (NULL != emsg) | ||
254 | { | ||
255 | signal_publish_error (pc->fi, pc, emsg); | ||
256 | GNUNET_FS_publish_sync_ (pc); | ||
257 | return; | ||
258 | } | ||
259 | if (NULL != uri) | ||
260 | { | ||
261 | /* sks publication, remember namespace URI */ | ||
262 | pc->fi->sks_uri = GNUNET_FS_uri_dup (uri); | ||
263 | } | ||
264 | GNUNET_assert (pc->qre == NULL); | ||
265 | if ((pc->dsh != NULL) && (pc->rid != 0)) | ||
266 | { | ||
267 | pc->qre = | ||
268 | GNUNET_DATASTORE_release_reserve (pc->dsh, pc->rid, UINT_MAX, UINT_MAX, | ||
269 | &finish_release_reserve, pc); | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | finish_release_reserve (pc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * We are almost done publishing the structure, | ||
280 | * add SBlocks (if needed). | ||
281 | * | ||
282 | * @param pc overall upload data | ||
283 | */ | ||
284 | static void | ||
285 | publish_sblock (struct GNUNET_FS_PublishContext *pc) | ||
286 | { | ||
287 | if (NULL != pc->ns) | ||
288 | pc->sks_pc = GNUNET_FS_publish_sks (pc->h, | ||
289 | pc->ns, | ||
290 | pc->nid, | ||
291 | pc->nuid, | ||
292 | pc->fi->meta, | ||
293 | pc->fi->chk_uri, | ||
294 | &pc->fi->bo, | ||
295 | pc->options, | ||
296 | &publish_sblocks_cont, pc); | ||
297 | else | ||
298 | publish_sblocks_cont (pc, NULL, NULL); | ||
299 | } | ||
300 | |||
301 | |||
302 | /** | ||
303 | * We've finished publishing a KBlock as part of a larger upload. | ||
304 | * Check the result and continue the larger upload. | ||
305 | * | ||
306 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
307 | * of the larger upload | ||
308 | * @param uri URI of the published blocks | ||
309 | * @param emsg NULL on success, otherwise error message | ||
310 | */ | ||
311 | static void | ||
312 | publish_kblocks_cont (void *cls, | ||
313 | const struct GNUNET_FS_Uri *uri, | ||
314 | const char *emsg) | ||
315 | { | ||
316 | struct GNUNET_FS_PublishContext *pc = cls; | ||
317 | struct GNUNET_FS_FileInformation *p = pc->fi_pos; | ||
318 | |||
319 | pc->ksk_pc = NULL; | ||
320 | if (NULL != emsg) | ||
321 | { | ||
322 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
323 | "Error uploading KSK blocks: %s\n", | ||
324 | emsg); | ||
325 | signal_publish_error (p, pc, emsg); | ||
326 | GNUNET_FS_file_information_sync_ (p); | ||
327 | GNUNET_FS_publish_sync_ (pc); | ||
328 | GNUNET_assert (NULL == pc->upload_task); | ||
329 | pc->upload_task = | ||
330 | GNUNET_SCHEDULER_add_with_priority | ||
331 | (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
332 | &GNUNET_FS_publish_main_, | ||
333 | pc); | ||
334 | return; | ||
335 | } | ||
336 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
337 | "KSK blocks published, moving on to next file\n"); | ||
338 | if (NULL != p->dir) | ||
339 | signal_publish_completion (p, pc); | ||
340 | /* move on to next file */ | ||
341 | if (NULL != p->next) | ||
342 | pc->fi_pos = p->next; | ||
343 | else | ||
344 | pc->fi_pos = p->dir; | ||
345 | GNUNET_FS_publish_sync_ (pc); | ||
346 | GNUNET_assert (NULL == pc->upload_task); | ||
347 | pc->upload_task = | ||
348 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
349 | &GNUNET_FS_publish_main_, pc); | ||
350 | } | ||
351 | |||
352 | |||
353 | /** | ||
354 | * Function called by the tree encoder to obtain | ||
355 | * a block of plaintext data (for the lowest level | ||
356 | * of the tree). | ||
357 | * | ||
358 | * @param cls our publishing context | ||
359 | * @param offset identifies which block to get | ||
360 | * @param max (maximum) number of bytes to get; returning | ||
361 | * fewer will also cause errors | ||
362 | * @param buf where to copy the plaintext buffer | ||
363 | * @param emsg location to store an error message (on error) | ||
364 | * @return number of bytes copied to buf, 0 on error | ||
365 | */ | ||
366 | static size_t | ||
367 | block_reader (void *cls, | ||
368 | uint64_t offset, | ||
369 | size_t max, | ||
370 | void *buf, | ||
371 | char **emsg) | ||
372 | { | ||
373 | struct GNUNET_FS_PublishContext *pc = cls; | ||
374 | struct GNUNET_FS_FileInformation *p; | ||
375 | const char *dd; | ||
376 | size_t pt_size; | ||
377 | |||
378 | p = pc->fi_pos; | ||
379 | if (GNUNET_YES == p->is_directory) | ||
380 | { | ||
381 | pt_size = GNUNET_MIN (max, p->data.dir.dir_size - offset); | ||
382 | dd = p->data.dir.dir_data; | ||
383 | GNUNET_memcpy (buf, &dd[offset], pt_size); | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | if (UINT64_MAX == offset) | ||
388 | { | ||
389 | if (&GNUNET_FS_data_reader_file_ == p->data.file.reader) | ||
390 | { | ||
391 | /* force closing the file to avoid keeping too many files open */ | ||
392 | p->data.file.reader (p->data.file.reader_cls, offset, 0, NULL, NULL); | ||
393 | } | ||
394 | return 0; | ||
395 | } | ||
396 | pt_size = GNUNET_MIN (max, p->data.file.file_size - offset); | ||
397 | if (0 == pt_size) | ||
398 | return 0; /* calling reader with pt_size==0 | ||
399 | * might free buf, so don't! */ | ||
400 | if (pt_size != | ||
401 | p->data.file.reader (p->data.file.reader_cls, offset, pt_size, buf, | ||
402 | emsg)) | ||
403 | return 0; | ||
404 | } | ||
405 | return pt_size; | ||
406 | } | ||
407 | |||
408 | |||
409 | /** | ||
410 | * The tree encoder has finished processing a | ||
411 | * file. Call it's finish method and deal with | ||
412 | * the final result. | ||
413 | * | ||
414 | * @param cls our publishing context | ||
415 | */ | ||
416 | static void | ||
417 | encode_cont (void *cls) | ||
418 | { | ||
419 | struct GNUNET_FS_PublishContext *pc = cls; | ||
420 | struct GNUNET_FS_FileInformation *p; | ||
421 | struct GNUNET_FS_ProgressInfo pi; | ||
422 | char *emsg; | ||
423 | uint64_t flen; | ||
424 | |||
425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
426 | "Finished with tree encoder\n"); | ||
427 | p = pc->fi_pos; | ||
428 | p->chk_uri = GNUNET_FS_tree_encoder_get_uri (p->te); | ||
429 | GNUNET_FS_file_information_sync_ (p); | ||
430 | GNUNET_FS_tree_encoder_finish (p->te, &emsg); | ||
431 | p->te = NULL; | ||
432 | if (NULL != emsg) | ||
433 | { | ||
434 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
435 | "Error during tree walk: %s\n", | ||
436 | emsg); | ||
437 | GNUNET_asprintf (&p->emsg, | ||
438 | _ ("Publishing failed: %s"), | ||
439 | emsg); | ||
440 | GNUNET_free (emsg); | ||
441 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
442 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
443 | pi.value.publish.specifics.error.message = p->emsg; | ||
444 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | /* final progress event */ | ||
449 | GNUNET_assert (NULL != p->chk_uri); | ||
450 | flen = GNUNET_FS_uri_chk_get_file_size (p->chk_uri); | ||
451 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; | ||
452 | pi.value.publish.specifics.progress.data = NULL; | ||
453 | pi.value.publish.specifics.progress.offset = flen; | ||
454 | pi.value.publish.specifics.progress.data_len = 0; | ||
455 | pi.value.publish.specifics.progress.depth = GNUNET_FS_compute_depth (flen); | ||
456 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, flen); | ||
457 | } | ||
458 | /* continue with main */ /* continue with main */ | ||
459 | GNUNET_assert (NULL == pc->upload_task); | ||
460 | pc->upload_task = | ||
461 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
462 | &GNUNET_FS_publish_main_, pc); | ||
463 | } | ||
464 | |||
465 | |||
466 | /** | ||
467 | * Function called asking for the current (encoded) | ||
468 | * block to be processed. After processing the | ||
469 | * client should either call #GNUNET_FS_tree_encoder_next | ||
470 | * or (on error) #GNUNET_FS_tree_encoder_finish. | ||
471 | * | ||
472 | * @param cls closure | ||
473 | * @param chk content hash key for the block | ||
474 | * @param offset offset of the block in the file | ||
475 | * @param depth depth of the block in the file, 0 for DBLOCK | ||
476 | * @param type type of the block (IBLOCK or DBLOCK) | ||
477 | * @param block the (encrypted) block | ||
478 | * @param block_size size of @a block (in bytes) | ||
479 | */ | ||
480 | static void | ||
481 | block_proc (void *cls, | ||
482 | const struct ContentHashKey *chk, | ||
483 | uint64_t offset, | ||
484 | unsigned int depth, | ||
485 | enum GNUNET_BLOCK_Type type, | ||
486 | const void *block, | ||
487 | uint16_t block_size) | ||
488 | { | ||
489 | struct GNUNET_FS_PublishContext *pc = cls; | ||
490 | struct GNUNET_FS_FileInformation *p; | ||
491 | struct OnDemandBlock odb; | ||
492 | |||
493 | p = pc->fi_pos; | ||
494 | if (NULL == pc->dsh) | ||
495 | { | ||
496 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
497 | "Waiting for datastore connection\n"); | ||
498 | GNUNET_assert (NULL == pc->upload_task); | ||
499 | pc->upload_task = | ||
500 | GNUNET_SCHEDULER_add_with_priority | ||
501 | (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); | ||
502 | return; | ||
503 | } | ||
504 | |||
505 | if ((GNUNET_YES != p->is_directory) && | ||
506 | (GNUNET_YES == p->data.file.do_index) && | ||
507 | (GNUNET_BLOCK_TYPE_FS_DBLOCK == type)) | ||
508 | { | ||
509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
510 | "Indexing block `%s' for offset %llu with index size %u\n", | ||
511 | GNUNET_h2s (&chk->query), | ||
512 | (unsigned long long) offset, | ||
513 | (unsigned int) sizeof(struct OnDemandBlock)); | ||
514 | odb.offset = GNUNET_htonll (offset); | ||
515 | odb.file_id = p->data.file.file_id; | ||
516 | GNUNET_assert (pc->qre == NULL); | ||
517 | pc->qre = | ||
518 | GNUNET_DATASTORE_put (pc->dsh, | ||
519 | (p->is_directory == GNUNET_YES) ? 0 : pc->rid, | ||
520 | &chk->query, | ||
521 | sizeof(struct OnDemandBlock), | ||
522 | &odb, | ||
523 | GNUNET_BLOCK_TYPE_FS_ONDEMAND, | ||
524 | p->bo.content_priority, | ||
525 | p->bo.anonymity_level, | ||
526 | p->bo.replication_level, | ||
527 | p->bo.expiration_time, | ||
528 | -2, 1, | ||
529 | &ds_put_cont, pc); | ||
530 | return; | ||
531 | } | ||
532 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
533 | "Publishing block `%s' for offset %llu with size %u\n", | ||
534 | GNUNET_h2s (&chk->query), | ||
535 | (unsigned long long) offset, | ||
536 | (unsigned int) block_size); | ||
537 | GNUNET_assert (pc->qre == NULL); | ||
538 | pc->qre = | ||
539 | GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 : | ||
540 | pc->rid, | ||
541 | &chk->query, | ||
542 | block_size, | ||
543 | block, | ||
544 | type, | ||
545 | p->bo.content_priority, | ||
546 | p->bo.anonymity_level, | ||
547 | p->bo.replication_level, | ||
548 | p->bo.expiration_time, | ||
549 | -2, 1, | ||
550 | &ds_put_cont, | ||
551 | pc); | ||
552 | } | ||
553 | |||
554 | |||
555 | /** | ||
556 | * Function called with information about our | ||
557 | * progress in computing the tree encoding. | ||
558 | * | ||
559 | * @param cls closure | ||
560 | * @param offset where are we in the file | ||
561 | * @param pt_block plaintext of the currently processed block | ||
562 | * @param pt_size size of @a pt_block | ||
563 | * @param depth depth of the block in the tree, 0 for DBLOCK | ||
564 | */ | ||
565 | static void | ||
566 | progress_proc (void *cls, uint64_t offset, | ||
567 | const void *pt_block, | ||
568 | size_t pt_size, | ||
569 | unsigned int depth) | ||
570 | { | ||
571 | struct GNUNET_FS_PublishContext *pc = cls; | ||
572 | struct GNUNET_FS_FileInformation *p; | ||
573 | struct GNUNET_FS_FileInformation *par; | ||
574 | struct GNUNET_FS_ProgressInfo pi; | ||
575 | |||
576 | p = pc->fi_pos; | ||
577 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; | ||
578 | pi.value.publish.specifics.progress.data = pt_block; | ||
579 | pi.value.publish.specifics.progress.offset = offset; | ||
580 | pi.value.publish.specifics.progress.data_len = pt_size; | ||
581 | pi.value.publish.specifics.progress.depth = depth; | ||
582 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, offset); | ||
583 | if ((0 != depth) || | ||
584 | (GNUNET_YES == p->is_directory)) | ||
585 | return; | ||
586 | while (NULL != (par = p->dir)) | ||
587 | { | ||
588 | p = par; | ||
589 | GNUNET_assert (GNUNET_YES == par->is_directory); | ||
590 | p->data.dir.contents_completed += pt_size; | ||
591 | pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY; | ||
592 | pi.value.publish.specifics.progress_directory.completed = | ||
593 | p->data.dir.contents_completed; | ||
594 | pi.value.publish.specifics.progress_directory.total = | ||
595 | p->data.dir.contents_size; | ||
596 | pi.value.publish.specifics.progress_directory.eta = | ||
597 | GNUNET_TIME_calculate_eta (p->start_time, | ||
598 | p | ||
599 | ->data.dir.contents_completed, | ||
600 | p | ||
601 | ->data.dir.contents_size); | ||
602 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | |||
607 | /** | ||
608 | * We are uploading a file or directory; load (if necessary) the next | ||
609 | * block into memory, encrypt it and send it to the FS service. Then | ||
610 | * continue with the main task. | ||
611 | * | ||
612 | * @param pc overall upload data | ||
613 | */ | ||
614 | static void | ||
615 | publish_content (struct GNUNET_FS_PublishContext *pc) | ||
616 | { | ||
617 | struct GNUNET_FS_FileInformation *p; | ||
618 | char *emsg; | ||
619 | struct GNUNET_FS_DirectoryBuilder *db; | ||
620 | struct GNUNET_FS_FileInformation *dirpos; | ||
621 | void *raw_data; | ||
622 | uint64_t size; | ||
623 | |||
624 | p = pc->fi_pos; | ||
625 | GNUNET_assert (NULL != p); | ||
626 | if (NULL == p->te) | ||
627 | { | ||
628 | if (GNUNET_YES == p->is_directory) | ||
629 | { | ||
630 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating directory\n"); | ||
631 | db = GNUNET_FS_directory_builder_create (p->meta); | ||
632 | dirpos = p->data.dir.entries; | ||
633 | while (NULL != dirpos) | ||
634 | { | ||
635 | if (GNUNET_YES == dirpos->is_directory) | ||
636 | { | ||
637 | raw_data = dirpos->data.dir.dir_data; | ||
638 | dirpos->data.dir.dir_data = NULL; | ||
639 | } | ||
640 | else | ||
641 | { | ||
642 | raw_data = NULL; | ||
643 | if ((dirpos->data.file.file_size < MAX_INLINE_SIZE) && | ||
644 | (dirpos->data.file.file_size > 0)) | ||
645 | { | ||
646 | raw_data = GNUNET_malloc (dirpos->data.file.file_size); | ||
647 | emsg = NULL; | ||
648 | if (dirpos->data.file.file_size != | ||
649 | dirpos->data.file.reader (dirpos->data.file.reader_cls, 0, | ||
650 | dirpos->data.file.file_size, raw_data, | ||
651 | &emsg)) | ||
652 | { | ||
653 | GNUNET_free (emsg); | ||
654 | GNUNET_free (raw_data); | ||
655 | raw_data = NULL; | ||
656 | } | ||
657 | dirpos->data.file.reader (dirpos->data.file.reader_cls, UINT64_MAX, | ||
658 | 0, 0, NULL); | ||
659 | } | ||
660 | } | ||
661 | GNUNET_FS_directory_builder_add (db, dirpos->chk_uri, dirpos->meta, | ||
662 | raw_data); | ||
663 | GNUNET_free (raw_data); | ||
664 | dirpos = dirpos->next; | ||
665 | } | ||
666 | GNUNET_free (p->data.dir.dir_data); | ||
667 | p->data.dir.dir_data = NULL; | ||
668 | p->data.dir.dir_size = 0; | ||
669 | GNUNET_FS_directory_builder_finish (db, &p->data.dir.dir_size, | ||
670 | &p->data.dir.dir_data); | ||
671 | GNUNET_FS_file_information_sync_ (p); | ||
672 | } | ||
673 | size = (GNUNET_YES == p->is_directory) ? p->data.dir.dir_size : | ||
674 | p->data.file.file_size; | ||
675 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
676 | "Creating tree encoder\n"); | ||
677 | p->te = | ||
678 | GNUNET_FS_tree_encoder_create (pc->h, size, pc, &block_reader, | ||
679 | &block_proc, &progress_proc, | ||
680 | &encode_cont); | ||
681 | } | ||
682 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
683 | "Processing next block from tree\n"); | ||
684 | GNUNET_FS_tree_encoder_next (p->te); | ||
685 | } | ||
686 | |||
687 | |||
688 | /** | ||
689 | * Check the response from the "fs" service to our 'start index' | ||
690 | * request. | ||
691 | * | ||
692 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
693 | * @param msg the response we got | ||
694 | */ | ||
695 | static int | ||
696 | check_index_start_failed (void *cls, | ||
697 | const struct GNUNET_MessageHeader *msg) | ||
698 | { | ||
699 | size_t msize = ntohs (msg->size) - sizeof(*msg); | ||
700 | const char *emsg = (const char *) &msg[1]; | ||
701 | |||
702 | if (emsg[msize - sizeof(struct GNUNET_MessageHeader) - 1] != '\0') | ||
703 | { | ||
704 | GNUNET_break (0); | ||
705 | return GNUNET_SYSERR; | ||
706 | } | ||
707 | return GNUNET_OK; | ||
708 | } | ||
709 | |||
710 | |||
711 | /** | ||
712 | * Process the response from the "fs" service to our 'start index' | ||
713 | * request. | ||
714 | * | ||
715 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
716 | * @param msg the response we got | ||
717 | */ | ||
718 | static void | ||
719 | handle_index_start_failed (void *cls, | ||
720 | const struct GNUNET_MessageHeader *msg) | ||
721 | { | ||
722 | struct GNUNET_FS_PublishContext *pc = cls; | ||
723 | struct GNUNET_FS_FileInformation *p; | ||
724 | const char *emsg = (const char *) &msg[1]; | ||
725 | char *msgtxt; | ||
726 | |||
727 | GNUNET_MQ_destroy (pc->mq); | ||
728 | pc->mq = NULL; | ||
729 | p = pc->fi_pos; | ||
730 | GNUNET_asprintf (&msgtxt, | ||
731 | _ ("Can not index file `%s': %s.\n"), | ||
732 | p->filename, | ||
733 | gettext (emsg)); | ||
734 | signal_publish_error (p, | ||
735 | pc, | ||
736 | msgtxt); | ||
737 | GNUNET_free (msgtxt); | ||
738 | GNUNET_FS_file_information_sync_ (p); | ||
739 | GNUNET_FS_publish_sync_ (pc); | ||
740 | } | ||
741 | |||
742 | |||
743 | /** | ||
744 | * Process the response from the "fs" service to our 'start index' | ||
745 | * request. | ||
746 | * | ||
747 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
748 | * @param msg the response we got | ||
749 | */ | ||
750 | static void | ||
751 | handle_index_start_ok (void *cls, | ||
752 | const struct GNUNET_MessageHeader *msg) | ||
753 | { | ||
754 | struct GNUNET_FS_PublishContext *pc = cls; | ||
755 | struct GNUNET_FS_FileInformation *p; | ||
756 | |||
757 | GNUNET_MQ_destroy (pc->mq); | ||
758 | pc->mq = NULL; | ||
759 | p = pc->fi_pos; | ||
760 | p->data.file.index_start_confirmed = GNUNET_YES; | ||
761 | GNUNET_FS_file_information_sync_ (p); | ||
762 | publish_content (pc); | ||
763 | } | ||
764 | |||
765 | |||
766 | /** | ||
767 | * Generic error handler, called with the appropriate error code and | ||
768 | * the same closure specified at the creation of the message queue. | ||
769 | * Not every message queue implementation supports an error handler. | ||
770 | * | ||
771 | * @param cls closure with the `struct GNUNET_FS_PublishContext *` | ||
772 | * @param error error code | ||
773 | */ | ||
774 | static void | ||
775 | index_mq_error_handler (void *cls, | ||
776 | enum GNUNET_MQ_Error error) | ||
777 | { | ||
778 | struct GNUNET_FS_PublishContext *pc = cls; | ||
779 | struct GNUNET_FS_FileInformation *p; | ||
780 | |||
781 | if (NULL != pc->mq) | ||
782 | { | ||
783 | GNUNET_MQ_destroy (pc->mq); | ||
784 | pc->mq = NULL; | ||
785 | } | ||
786 | p = pc->fi_pos; | ||
787 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
788 | _ ("Can not index file `%s': %s. Will try to insert instead.\n"), | ||
789 | p->filename, | ||
790 | _ ("error on index-start request to `fs' service")); | ||
791 | p->data.file.do_index = GNUNET_NO; | ||
792 | GNUNET_FS_file_information_sync_ (p); | ||
793 | publish_content (pc); | ||
794 | } | ||
795 | |||
796 | |||
797 | /** | ||
798 | * Function called once the hash computation over an | ||
799 | * indexed file has completed. | ||
800 | * | ||
801 | * @param cls closure, our publishing context | ||
802 | * @param res resulting hash, NULL on error | ||
803 | */ | ||
804 | static void | ||
805 | hash_for_index_cb (void *cls, | ||
806 | const struct GNUNET_HashCode *res) | ||
807 | { | ||
808 | struct GNUNET_FS_PublishContext *pc = cls; | ||
809 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
810 | GNUNET_MQ_hd_fixed_size (index_start_ok, | ||
811 | GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK, | ||
812 | struct GNUNET_MessageHeader, | ||
813 | pc), | ||
814 | GNUNET_MQ_hd_var_size (index_start_failed, | ||
815 | GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED, | ||
816 | struct GNUNET_MessageHeader, | ||
817 | pc), | ||
818 | GNUNET_MQ_handler_end () | ||
819 | }; | ||
820 | struct GNUNET_FS_FileInformation *p; | ||
821 | struct GNUNET_MQ_Envelope *env; | ||
822 | struct IndexStartMessage *ism; | ||
823 | size_t slen; | ||
824 | uint64_t dev; | ||
825 | uint64_t ino; | ||
826 | char *fn; | ||
827 | |||
828 | pc->fhc = NULL; | ||
829 | p = pc->fi_pos; | ||
830 | if (NULL == res) | ||
831 | { | ||
832 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
833 | _ ( | ||
834 | "Can not index file `%s': %s. Will try to insert instead.\n"), | ||
835 | p->filename, | ||
836 | _ ("failed to compute hash")); | ||
837 | p->data.file.do_index = GNUNET_NO; | ||
838 | GNUNET_FS_file_information_sync_ (p); | ||
839 | publish_content (pc); | ||
840 | return; | ||
841 | } | ||
842 | if (GNUNET_YES == p->data.file.index_start_confirmed) | ||
843 | { | ||
844 | publish_content (pc); | ||
845 | return; | ||
846 | } | ||
847 | fn = GNUNET_STRINGS_filename_expand (p->filename); | ||
848 | GNUNET_assert (fn != NULL); | ||
849 | slen = strlen (fn) + 1; | ||
850 | if (slen >= | ||
851 | GNUNET_MAX_MESSAGE_SIZE - sizeof(struct IndexStartMessage)) | ||
852 | { | ||
853 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
854 | _ | ||
855 | ("Can not index file `%s': %s. Will try to insert instead.\n"), | ||
856 | fn, _ ("filename too long")); | ||
857 | GNUNET_free (fn); | ||
858 | p->data.file.do_index = GNUNET_NO; | ||
859 | GNUNET_FS_file_information_sync_ (p); | ||
860 | publish_content (pc); | ||
861 | return; | ||
862 | } | ||
863 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
864 | "Hash of indexed file `%s' is `%s'\n", | ||
865 | p->filename, | ||
866 | GNUNET_h2s (res)); | ||
867 | if (0 != (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) | ||
868 | { | ||
869 | p->data.file.file_id = *res; | ||
870 | p->data.file.have_hash = GNUNET_YES; | ||
871 | p->data.file.index_start_confirmed = GNUNET_YES; | ||
872 | GNUNET_FS_file_information_sync_ (p); | ||
873 | publish_content (pc); | ||
874 | GNUNET_free (fn); | ||
875 | return; | ||
876 | } | ||
877 | pc->mq = GNUNET_CLIENT_connect (pc->h->cfg, | ||
878 | "fs", | ||
879 | handlers, | ||
880 | &index_mq_error_handler, | ||
881 | pc); | ||
882 | if (NULL == pc->mq) | ||
883 | { | ||
884 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
885 | _ ( | ||
886 | "Can not index file `%s': %s. Will try to insert instead.\n"), | ||
887 | p->filename, | ||
888 | _ ("could not connect to `fs' service")); | ||
889 | p->data.file.do_index = GNUNET_NO; | ||
890 | publish_content (pc); | ||
891 | GNUNET_free (fn); | ||
892 | return; | ||
893 | } | ||
894 | if (p->data.file.have_hash != GNUNET_YES) | ||
895 | { | ||
896 | p->data.file.file_id = *res; | ||
897 | p->data.file.have_hash = GNUNET_YES; | ||
898 | GNUNET_FS_file_information_sync_ (p); | ||
899 | } | ||
900 | env = GNUNET_MQ_msg_extra (ism, | ||
901 | slen, | ||
902 | GNUNET_MESSAGE_TYPE_FS_INDEX_START); | ||
903 | if (GNUNET_OK == | ||
904 | GNUNET_DISK_file_get_identifiers (p->filename, | ||
905 | &dev, | ||
906 | &ino)) | ||
907 | { | ||
908 | ism->device = GNUNET_htonll (dev); | ||
909 | ism->inode = GNUNET_htonll (ino); | ||
910 | } | ||
911 | else | ||
912 | { | ||
913 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
914 | _ ("Failed to get file identifiers for `%s'\n"), | ||
915 | p->filename); | ||
916 | } | ||
917 | ism->file_id = *res; | ||
918 | GNUNET_memcpy (&ism[1], | ||
919 | fn, | ||
920 | slen); | ||
921 | GNUNET_free (fn); | ||
922 | GNUNET_MQ_send (pc->mq, | ||
923 | env); | ||
924 | } | ||
925 | |||
926 | |||
927 | /** | ||
928 | * We've computed the CHK/LOC URI, now publish the KSKs (if applicable). | ||
929 | * | ||
930 | * @param pc publishing context to do this for | ||
931 | */ | ||
932 | static void | ||
933 | publish_kblocks (struct GNUNET_FS_PublishContext *pc) | ||
934 | { | ||
935 | struct GNUNET_FS_FileInformation *p; | ||
936 | |||
937 | p = pc->fi_pos; | ||
938 | /* upload of "p" complete, publish KBlocks! */ | ||
939 | if (NULL != p->keywords) | ||
940 | { | ||
941 | pc->ksk_pc = GNUNET_FS_publish_ksk (pc->h, | ||
942 | p->keywords, | ||
943 | p->meta, | ||
944 | p->chk_uri, | ||
945 | &p->bo, | ||
946 | pc->options, | ||
947 | &publish_kblocks_cont, | ||
948 | pc); | ||
949 | } | ||
950 | else | ||
951 | { | ||
952 | publish_kblocks_cont (pc, p->chk_uri, NULL); | ||
953 | } | ||
954 | } | ||
955 | |||
956 | |||
957 | /** | ||
958 | * Process the response from the "fs" service to our LOC sign request. | ||
959 | * | ||
960 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
961 | * @param sig the response we got | ||
962 | */ | ||
963 | static void | ||
964 | handle_signature_response (void *cls, | ||
965 | const struct ResponseLocSignatureMessage *sig) | ||
966 | { | ||
967 | struct GNUNET_FS_PublishContext *pc = cls; | ||
968 | struct GNUNET_FS_FileInformation *p; | ||
969 | |||
970 | p = pc->fi_pos; | ||
971 | p->chk_uri->type = GNUNET_FS_URI_LOC; | ||
972 | /* p->data.loc.fi kept from CHK before */ | ||
973 | p->chk_uri->data.loc.peer = sig->peer; | ||
974 | p->chk_uri->data.loc.expirationTime | ||
975 | = GNUNET_TIME_absolute_ntoh (sig->expiration_time); | ||
976 | p->chk_uri->data.loc.contentSignature = sig->signature; | ||
977 | GNUNET_FS_file_information_sync_ (p); | ||
978 | GNUNET_FS_publish_sync_ (pc); | ||
979 | publish_kblocks (pc); | ||
980 | } | ||
981 | |||
982 | |||
983 | /** | ||
984 | * Generic error handler, called with the appropriate error code and | ||
985 | * the same closure specified at the creation of the message queue. | ||
986 | * Not every message queue implementation supports an error handler. | ||
987 | * | ||
988 | * @param cls closure with the `struct GNUNET_FS_PublishContext *` | ||
989 | * @param error error code | ||
990 | */ | ||
991 | static void | ||
992 | loc_mq_error_handler (void *cls, | ||
993 | enum GNUNET_MQ_Error error) | ||
994 | { | ||
995 | struct GNUNET_FS_PublishContext *pc = cls; | ||
996 | |||
997 | if (NULL != pc->mq) | ||
998 | { | ||
999 | GNUNET_MQ_destroy (pc->mq); | ||
1000 | pc->mq = NULL; | ||
1001 | } | ||
1002 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1003 | _ ("Can not create LOC URI. Will continue with CHK instead.\n")); | ||
1004 | publish_kblocks (pc); | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /** | ||
1009 | * We're publishing without anonymity. Contact the FS service | ||
1010 | * to create a signed LOC URI for further processing, then | ||
1011 | * continue with KSKs. | ||
1012 | * | ||
1013 | * @param pc the publishing context do to this for | ||
1014 | */ | ||
1015 | static void | ||
1016 | create_loc_uri (struct GNUNET_FS_PublishContext *pc) | ||
1017 | { | ||
1018 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1019 | GNUNET_MQ_hd_fixed_size (signature_response, | ||
1020 | GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE, | ||
1021 | struct ResponseLocSignatureMessage, | ||
1022 | pc), | ||
1023 | GNUNET_MQ_handler_end () | ||
1024 | }; | ||
1025 | struct GNUNET_MQ_Envelope *env; | ||
1026 | struct RequestLocSignatureMessage *req; | ||
1027 | struct GNUNET_FS_FileInformation *p; | ||
1028 | |||
1029 | if (NULL != pc->mq) | ||
1030 | GNUNET_MQ_destroy (pc->mq); | ||
1031 | pc->mq = GNUNET_CLIENT_connect (pc->h->cfg, | ||
1032 | "fs", | ||
1033 | handlers, | ||
1034 | &loc_mq_error_handler, | ||
1035 | pc); | ||
1036 | if (NULL == pc->mq) | ||
1037 | { | ||
1038 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1039 | _ ( | ||
1040 | "Can not create LOC URI. Will continue with CHK instead.\n")); | ||
1041 | publish_kblocks (pc); | ||
1042 | return; | ||
1043 | } | ||
1044 | p = pc->fi_pos; | ||
1045 | env = GNUNET_MQ_msg (req, | ||
1046 | GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN); | ||
1047 | req->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); | ||
1048 | req->expiration_time = GNUNET_TIME_absolute_hton (p->bo.expiration_time); | ||
1049 | req->chk = p->chk_uri->data.chk.chk; | ||
1050 | req->file_length = GNUNET_htonll (p->chk_uri->data.chk.file_length); | ||
1051 | GNUNET_MQ_send (pc->mq, | ||
1052 | env); | ||
1053 | } | ||
1054 | |||
1055 | |||
1056 | /** | ||
1057 | * Main function that performs the upload. | ||
1058 | * | ||
1059 | * @param cls `struct GNUNET_FS_PublishContext *` identifies the upload | ||
1060 | */ | ||
1061 | void | ||
1062 | GNUNET_FS_publish_main_ (void *cls) | ||
1063 | { | ||
1064 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1065 | struct GNUNET_FS_ProgressInfo pi; | ||
1066 | struct GNUNET_FS_FileInformation *p; | ||
1067 | char *fn; | ||
1068 | |||
1069 | pc->upload_task = NULL; | ||
1070 | p = pc->fi_pos; | ||
1071 | if (NULL == p) | ||
1072 | { | ||
1073 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1074 | "Publishing complete, now publishing SKS and KSK blocks.\n"); | ||
1075 | /* upload of entire hierarchy complete, | ||
1076 | * publish namespace entries */ | ||
1077 | GNUNET_FS_publish_sync_ (pc); | ||
1078 | publish_sblock (pc); | ||
1079 | return; | ||
1080 | } | ||
1081 | /* find starting position */ | ||
1082 | while ((GNUNET_YES == p->is_directory) && | ||
1083 | (NULL != p->data.dir.entries) && | ||
1084 | (NULL == p->emsg) && | ||
1085 | (NULL == p->data.dir.entries->chk_uri)) | ||
1086 | { | ||
1087 | p = p->data.dir.entries; | ||
1088 | pc->fi_pos = p; | ||
1089 | GNUNET_FS_publish_sync_ (pc); | ||
1090 | } | ||
1091 | /* abort on error */ | ||
1092 | if (NULL != p->emsg) | ||
1093 | { | ||
1094 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1095 | "Error uploading: %s\n", | ||
1096 | p->emsg); | ||
1097 | /* error with current file, abort all | ||
1098 | * related files as well! */ | ||
1099 | while (NULL != p->dir) | ||
1100 | { | ||
1101 | fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta, | ||
1102 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); | ||
1103 | p = p->dir; | ||
1104 | if (fn != NULL) | ||
1105 | { | ||
1106 | GNUNET_asprintf (&p->emsg, | ||
1107 | _ ("Recursive upload failed at `%s': %s"), | ||
1108 | fn, | ||
1109 | p->emsg); | ||
1110 | GNUNET_free (fn); | ||
1111 | } | ||
1112 | else | ||
1113 | { | ||
1114 | GNUNET_asprintf (&p->emsg, | ||
1115 | _ ("Recursive upload failed: %s"), | ||
1116 | p->emsg); | ||
1117 | } | ||
1118 | pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; | ||
1119 | pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; | ||
1120 | pi.value.publish.specifics.error.message = p->emsg; | ||
1121 | p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); | ||
1122 | } | ||
1123 | pc->all_done = GNUNET_YES; | ||
1124 | GNUNET_FS_publish_sync_ (pc); | ||
1125 | return; | ||
1126 | } | ||
1127 | /* handle completion */ | ||
1128 | if (NULL != p->chk_uri) | ||
1129 | { | ||
1130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1131 | "File upload complete, now publishing KSK blocks.\n"); | ||
1132 | GNUNET_FS_publish_sync_ (pc); | ||
1133 | |||
1134 | if ((0 == p->bo.anonymity_level) && | ||
1135 | (GNUNET_YES != | ||
1136 | GNUNET_FS_uri_test_loc (p->chk_uri))) | ||
1137 | { | ||
1138 | /* zero anonymity, box CHK URI in LOC URI */ | ||
1139 | create_loc_uri (pc); | ||
1140 | } | ||
1141 | else | ||
1142 | { | ||
1143 | publish_kblocks (pc); | ||
1144 | } | ||
1145 | return; | ||
1146 | } | ||
1147 | if ((GNUNET_YES != p->is_directory) && (p->data.file.do_index)) | ||
1148 | { | ||
1149 | if (NULL == p->filename) | ||
1150 | { | ||
1151 | p->data.file.do_index = GNUNET_NO; | ||
1152 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1153 | _ ( | ||
1154 | "Can not index file `%s': %s. Will try to insert instead.\n"), | ||
1155 | "<no-name>", | ||
1156 | _ ("needs to be an actual file")); | ||
1157 | GNUNET_FS_file_information_sync_ (p); | ||
1158 | publish_content (pc); | ||
1159 | return; | ||
1160 | } | ||
1161 | if (p->data.file.have_hash) | ||
1162 | { | ||
1163 | hash_for_index_cb (pc, &p->data.file.file_id); | ||
1164 | } | ||
1165 | else | ||
1166 | { | ||
1167 | p->start_time = GNUNET_TIME_absolute_get (); | ||
1168 | pc->fhc = | ||
1169 | GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, p->filename, | ||
1170 | HASHING_BLOCKSIZE, &hash_for_index_cb, pc); | ||
1171 | } | ||
1172 | return; | ||
1173 | } | ||
1174 | publish_content (pc); | ||
1175 | } | ||
1176 | |||
1177 | |||
1178 | /** | ||
1179 | * Signal the FS's progress function that we are starting | ||
1180 | * an upload. | ||
1181 | * | ||
1182 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
1183 | * @param fi the entry in the publish-structure | ||
1184 | * @param length length of the file or directory | ||
1185 | * @param meta metadata for the file or directory (can be modified) | ||
1186 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1187 | * @param bo block options | ||
1188 | * @param do_index should we index? | ||
1189 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1190 | * @return #GNUNET_OK to continue (always) | ||
1191 | */ | ||
1192 | static int | ||
1193 | fip_signal_start (void *cls, | ||
1194 | struct GNUNET_FS_FileInformation *fi, | ||
1195 | uint64_t length, | ||
1196 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1197 | struct GNUNET_FS_Uri **uri, | ||
1198 | struct GNUNET_FS_BlockOptions *bo, | ||
1199 | int *do_index, | ||
1200 | void **client_info) | ||
1201 | { | ||
1202 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1203 | struct GNUNET_FS_ProgressInfo pi; | ||
1204 | unsigned int kc; | ||
1205 | uint64_t left; | ||
1206 | |||
1207 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1208 | { | ||
1209 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1210 | return GNUNET_OK; | ||
1211 | } | ||
1212 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1213 | "Starting publish operation\n"); | ||
1214 | if (*do_index) | ||
1215 | { | ||
1216 | /* space for on-demand blocks */ | ||
1217 | pc->reserve_space += | ||
1218 | ((length + DBLOCK_SIZE | ||
1219 | - 1) / DBLOCK_SIZE) * sizeof(struct OnDemandBlock); | ||
1220 | } | ||
1221 | else | ||
1222 | { | ||
1223 | /* space for DBlocks */ | ||
1224 | pc->reserve_space += length; | ||
1225 | } | ||
1226 | /* entries for IBlocks and DBlocks, space for IBlocks */ | ||
1227 | left = length; | ||
1228 | while (1) | ||
1229 | { | ||
1230 | left = (left + DBLOCK_SIZE - 1) / DBLOCK_SIZE; | ||
1231 | pc->reserve_entries += left; | ||
1232 | if (left <= 1) | ||
1233 | break; | ||
1234 | left = left * sizeof(struct ContentHashKey); | ||
1235 | pc->reserve_space += left; | ||
1236 | } | ||
1237 | pc->reserve_entries++; | ||
1238 | /* entries and space for keywords */ | ||
1239 | if (NULL != *uri) | ||
1240 | { | ||
1241 | kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri); | ||
1242 | pc->reserve_entries += kc; | ||
1243 | pc->reserve_space += GNUNET_MAX_MESSAGE_SIZE * kc; | ||
1244 | } | ||
1245 | pi.status = GNUNET_FS_STATUS_PUBLISH_START; | ||
1246 | *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); | ||
1247 | GNUNET_FS_file_information_sync_ (fi); | ||
1248 | if ((fi->is_directory) && (fi->dir != NULL)) | ||
1249 | { | ||
1250 | /* We are a directory, and we are not top-level; process entries in directory */ | ||
1251 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1252 | GNUNET_FS_file_information_inspect (fi, &fip_signal_start, pc); | ||
1253 | } | ||
1254 | return GNUNET_OK; | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | /** | ||
1259 | * Actually signal the FS's progress function that we are suspending | ||
1260 | * an upload. | ||
1261 | * | ||
1262 | * @param fi the entry in the publish-structure | ||
1263 | * @param pc the publish context of which a file is being suspended | ||
1264 | */ | ||
1265 | static void | ||
1266 | suspend_operation (struct GNUNET_FS_FileInformation *fi, | ||
1267 | struct GNUNET_FS_PublishContext *pc) | ||
1268 | { | ||
1269 | struct GNUNET_FS_ProgressInfo pi; | ||
1270 | uint64_t off; | ||
1271 | |||
1272 | if (NULL != pc->ksk_pc) | ||
1273 | { | ||
1274 | GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); | ||
1275 | pc->ksk_pc = NULL; | ||
1276 | } | ||
1277 | if (NULL != pc->sks_pc) | ||
1278 | { | ||
1279 | GNUNET_FS_publish_sks_cancel (pc->sks_pc); | ||
1280 | pc->sks_pc = NULL; | ||
1281 | } | ||
1282 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1283 | "Suspending publish operation\n"); | ||
1284 | GNUNET_free (fi->serialization); | ||
1285 | fi->serialization = NULL; | ||
1286 | off = (NULL == fi->chk_uri) ? 0 : (GNUNET_YES == fi->is_directory) ? | ||
1287 | fi->data.dir.dir_size : fi->data.file.file_size; | ||
1288 | pi.status = GNUNET_FS_STATUS_PUBLISH_SUSPEND; | ||
1289 | GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); | ||
1290 | if (NULL != pc->qre) | ||
1291 | { | ||
1292 | GNUNET_DATASTORE_cancel (pc->qre); | ||
1293 | pc->qre = NULL; | ||
1294 | } | ||
1295 | if (NULL != pc->dsh) | ||
1296 | { | ||
1297 | GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); | ||
1298 | pc->dsh = NULL; | ||
1299 | } | ||
1300 | pc->rid = 0; | ||
1301 | } | ||
1302 | |||
1303 | |||
1304 | /** | ||
1305 | * Signal the FS's progress function that we are suspending | ||
1306 | * an upload. Performs the recursion. | ||
1307 | * | ||
1308 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
1309 | * @param fi the entry in the publish-structure | ||
1310 | * @param length length of the file or directory | ||
1311 | * @param meta metadata for the file or directory (can be modified) | ||
1312 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1313 | * @param bo block options | ||
1314 | * @param do_index should we index? | ||
1315 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1316 | * @return #GNUNET_OK to continue (always) | ||
1317 | */ | ||
1318 | static int | ||
1319 | fip_signal_suspend (void *cls, | ||
1320 | struct GNUNET_FS_FileInformation *fi, | ||
1321 | uint64_t length, | ||
1322 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1323 | struct GNUNET_FS_Uri **uri, | ||
1324 | struct GNUNET_FS_BlockOptions *bo, | ||
1325 | int *do_index, | ||
1326 | void **client_info) | ||
1327 | { | ||
1328 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1329 | |||
1330 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1331 | { | ||
1332 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1333 | return GNUNET_OK; | ||
1334 | } | ||
1335 | if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) | ||
1336 | { | ||
1337 | /* process entries in directory */ | ||
1338 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1339 | GNUNET_FS_file_information_inspect (fi, &fip_signal_suspend, pc); | ||
1340 | } | ||
1341 | suspend_operation (fi, pc); | ||
1342 | *client_info = NULL; | ||
1343 | return GNUNET_OK; | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | /** | ||
1348 | * Create SUSPEND event for the given publish operation | ||
1349 | * and then clean up our state (without stop signal). | ||
1350 | * | ||
1351 | * @param cls the `struct GNUNET_FS_PublishContext` to signal for | ||
1352 | */ | ||
1353 | void | ||
1354 | GNUNET_FS_publish_signal_suspend_ (void *cls) | ||
1355 | { | ||
1356 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1357 | |||
1358 | if (NULL != pc->upload_task) | ||
1359 | { | ||
1360 | GNUNET_SCHEDULER_cancel (pc->upload_task); | ||
1361 | pc->upload_task = NULL; | ||
1362 | } | ||
1363 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1364 | GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_suspend, pc); | ||
1365 | suspend_operation (pc->fi, pc); | ||
1366 | GNUNET_FS_end_top (pc->h, pc->top); | ||
1367 | pc->top = NULL; | ||
1368 | publish_cleanup (pc); | ||
1369 | } | ||
1370 | |||
1371 | |||
1372 | /** | ||
1373 | * We have gotten a reply for our space reservation request. | ||
1374 | * Either fail (insufficient space) or start publishing for good. | ||
1375 | * | ||
1376 | * @param cls the `struct GNUNET_FS_PublishContext *` | ||
1377 | * @param success positive reservation ID on success | ||
1378 | * @param min_expiration minimum expiration time required for content to be stored | ||
1379 | * @param msg error message on error, otherwise NULL | ||
1380 | */ | ||
1381 | static void | ||
1382 | finish_reserve (void *cls, | ||
1383 | int success, | ||
1384 | struct GNUNET_TIME_Absolute min_expiration, | ||
1385 | const char *msg) | ||
1386 | { | ||
1387 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1388 | |||
1389 | pc->qre = NULL; | ||
1390 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1391 | "Reservation complete (%d)!\n", | ||
1392 | success); | ||
1393 | if ((msg != NULL) || (success <= 0)) | ||
1394 | { | ||
1395 | GNUNET_asprintf (&pc->fi->emsg, | ||
1396 | _ ("Datastore failure: %s"), | ||
1397 | msg); | ||
1398 | signal_publish_error (pc->fi, pc, pc->fi->emsg); | ||
1399 | return; | ||
1400 | } | ||
1401 | pc->rid = success; | ||
1402 | GNUNET_assert (NULL == pc->upload_task); | ||
1403 | pc->upload_task = | ||
1404 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, | ||
1405 | &GNUNET_FS_publish_main_, pc); | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | /** | ||
1410 | * Calculate the total size of all of the files in the directory structure. | ||
1411 | * | ||
1412 | * @param fi file structure to traverse | ||
1413 | */ | ||
1414 | static uint64_t | ||
1415 | compute_contents_size (struct GNUNET_FS_FileInformation *fi) | ||
1416 | { | ||
1417 | struct GNUNET_FS_FileInformation *ent; | ||
1418 | |||
1419 | if (GNUNET_YES != fi->is_directory) | ||
1420 | return fi->data.file.file_size; | ||
1421 | fi->data.dir.contents_size = 0; | ||
1422 | for (ent = fi->data.dir.entries; NULL != ent; ent = ent->next) | ||
1423 | fi->data.dir.contents_size += compute_contents_size (ent); | ||
1424 | return fi->data.dir.contents_size; | ||
1425 | } | ||
1426 | |||
1427 | |||
1428 | /** | ||
1429 | * Publish a file or directory. | ||
1430 | * | ||
1431 | * @param h handle to the file sharing subsystem | ||
1432 | * @param fi information about the file or directory structure to publish | ||
1433 | * @param ns namespace to publish the file in, NULL for no namespace | ||
1434 | * @param nid identifier to use for the published content in the namespace | ||
1435 | * (can be NULL, must be NULL if namespace is NULL) | ||
1436 | * @param nuid update-identifier that will be used for future updates | ||
1437 | * (can be NULL, must be NULL if namespace or nid is NULL) | ||
1438 | * @param options options for the publication | ||
1439 | * @return context that can be used to control the publish operation | ||
1440 | */ | ||
1441 | struct GNUNET_FS_PublishContext * | ||
1442 | GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h, | ||
1443 | struct GNUNET_FS_FileInformation *fi, | ||
1444 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, | ||
1445 | const char *nid, | ||
1446 | const char *nuid, | ||
1447 | enum GNUNET_FS_PublishOptions options) | ||
1448 | { | ||
1449 | struct GNUNET_FS_PublishContext *ret; | ||
1450 | struct GNUNET_DATASTORE_Handle *dsh; | ||
1451 | |||
1452 | GNUNET_assert (NULL != h); | ||
1453 | compute_contents_size (fi); | ||
1454 | if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) | ||
1455 | { | ||
1456 | dsh = GNUNET_DATASTORE_connect (h->cfg); | ||
1457 | if (NULL == dsh) | ||
1458 | return NULL; | ||
1459 | } | ||
1460 | else | ||
1461 | { | ||
1462 | dsh = NULL; | ||
1463 | } | ||
1464 | ret = GNUNET_new (struct GNUNET_FS_PublishContext); | ||
1465 | ret->dsh = dsh; | ||
1466 | ret->h = h; | ||
1467 | ret->fi = fi; | ||
1468 | if (NULL != ns) | ||
1469 | { | ||
1470 | ret->ns = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey); | ||
1471 | *ret->ns = *ns; | ||
1472 | GNUNET_assert (NULL != nid); | ||
1473 | ret->nid = GNUNET_strdup (nid); | ||
1474 | if (NULL != nuid) | ||
1475 | ret->nuid = GNUNET_strdup (nuid); | ||
1476 | } | ||
1477 | ret->options = options; | ||
1478 | /* signal start */ | ||
1479 | GNUNET_FS_file_information_inspect (ret->fi, &fip_signal_start, ret); | ||
1480 | ret->fi_pos = ret->fi; | ||
1481 | ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, ret); | ||
1482 | GNUNET_FS_publish_sync_ (ret); | ||
1483 | if (NULL != ret->dsh) | ||
1484 | { | ||
1485 | GNUNET_assert (NULL == ret->qre); | ||
1486 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1487 | _ ( | ||
1488 | "Reserving space for %u entries and %llu bytes for publication\n"), | ||
1489 | (unsigned int) ret->reserve_entries, | ||
1490 | (unsigned long long) ret->reserve_space); | ||
1491 | ret->qre = | ||
1492 | GNUNET_DATASTORE_reserve (ret->dsh, ret->reserve_space, | ||
1493 | ret->reserve_entries, | ||
1494 | &finish_reserve, | ||
1495 | ret); | ||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | GNUNET_assert (NULL == ret->upload_task); | ||
1500 | ret->upload_task = | ||
1501 | GNUNET_SCHEDULER_add_with_priority | ||
1502 | (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, ret); | ||
1503 | } | ||
1504 | return ret; | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | /** | ||
1509 | * Signal the FS's progress function that we are stopping | ||
1510 | * an upload. | ||
1511 | * | ||
1512 | * @param cls closure (of type `struct GNUNET_FS_PublishContext *`) | ||
1513 | * @param fi the entry in the publish-structure | ||
1514 | * @param length length of the file or directory | ||
1515 | * @param meta metadata for the file or directory (can be modified) | ||
1516 | * @param uri pointer to the keywords that will be used for this entry (can be modified) | ||
1517 | * @param bo block options (can be modified) | ||
1518 | * @param do_index should we index? | ||
1519 | * @param client_info pointer to client context set upon creation (can be modified) | ||
1520 | * @return #GNUNET_OK to continue (always) | ||
1521 | */ | ||
1522 | static int | ||
1523 | fip_signal_stop (void *cls, | ||
1524 | struct GNUNET_FS_FileInformation *fi, | ||
1525 | uint64_t length, | ||
1526 | struct GNUNET_CONTAINER_MetaData *meta, | ||
1527 | struct GNUNET_FS_Uri **uri, | ||
1528 | struct GNUNET_FS_BlockOptions *bo, | ||
1529 | int *do_index, void **client_info) | ||
1530 | { | ||
1531 | struct GNUNET_FS_PublishContext *pc = cls; | ||
1532 | struct GNUNET_FS_ProgressInfo pi; | ||
1533 | uint64_t off; | ||
1534 | |||
1535 | if (GNUNET_YES == pc->skip_next_fi_callback) | ||
1536 | { | ||
1537 | pc->skip_next_fi_callback = GNUNET_NO; | ||
1538 | return GNUNET_OK; | ||
1539 | } | ||
1540 | if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) | ||
1541 | { | ||
1542 | /* process entries in directory first */ | ||
1543 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1544 | GNUNET_FS_file_information_inspect (fi, &fip_signal_stop, pc); | ||
1545 | } | ||
1546 | if (NULL != fi->serialization) | ||
1547 | { | ||
1548 | GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, | ||
1549 | fi->serialization); | ||
1550 | GNUNET_free (fi->serialization); | ||
1551 | fi->serialization = NULL; | ||
1552 | } | ||
1553 | off = (fi->chk_uri == NULL) ? 0 : length; | ||
1554 | pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; | ||
1555 | GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); | ||
1556 | *client_info = NULL; | ||
1557 | return GNUNET_OK; | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | /** | ||
1562 | * Stop an upload. Will abort incomplete uploads (but | ||
1563 | * not remove blocks that have already been published) or | ||
1564 | * simply clean up the state for completed uploads. | ||
1565 | * Must NOT be called from within the event callback! | ||
1566 | * | ||
1567 | * @param pc context for the upload to stop | ||
1568 | */ | ||
1569 | void | ||
1570 | GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc) | ||
1571 | { | ||
1572 | struct GNUNET_FS_ProgressInfo pi; | ||
1573 | uint64_t off; | ||
1574 | |||
1575 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1576 | "Publish stop called\n"); | ||
1577 | GNUNET_FS_end_top (pc->h, pc->top); | ||
1578 | if (NULL != pc->ksk_pc) | ||
1579 | { | ||
1580 | GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); | ||
1581 | pc->ksk_pc = NULL; | ||
1582 | } | ||
1583 | if (NULL != pc->sks_pc) | ||
1584 | { | ||
1585 | GNUNET_FS_publish_sks_cancel (pc->sks_pc); | ||
1586 | pc->sks_pc = NULL; | ||
1587 | } | ||
1588 | if (NULL != pc->upload_task) | ||
1589 | { | ||
1590 | GNUNET_SCHEDULER_cancel (pc->upload_task); | ||
1591 | pc->upload_task = NULL; | ||
1592 | } | ||
1593 | pc->skip_next_fi_callback = GNUNET_YES; | ||
1594 | GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_stop, pc); | ||
1595 | |||
1596 | if (NULL != pc->fi->serialization) | ||
1597 | { | ||
1598 | GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, | ||
1599 | pc->fi->serialization); | ||
1600 | GNUNET_free (pc->fi->serialization); | ||
1601 | pc->fi->serialization = NULL; | ||
1602 | } | ||
1603 | off = (NULL == pc->fi->chk_uri) ? 0 : GNUNET_ntohll ( | ||
1604 | pc->fi->chk_uri->data.chk.file_length); | ||
1605 | |||
1606 | if (NULL != pc->serialization) | ||
1607 | { | ||
1608 | GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, | ||
1609 | pc->serialization); | ||
1610 | GNUNET_free (pc->serialization); | ||
1611 | pc->serialization = NULL; | ||
1612 | } | ||
1613 | if (NULL != pc->qre) | ||
1614 | { | ||
1615 | GNUNET_DATASTORE_cancel (pc->qre); | ||
1616 | pc->qre = NULL; | ||
1617 | } | ||
1618 | pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; | ||
1619 | GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi, off)); | ||
1620 | publish_cleanup (pc); | ||
1621 | } | ||
1622 | |||
1623 | |||
1624 | /* end of fs_publish.c */ | ||