aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/fs_api.c')
-rw-r--r--src/fs/fs_api.c3349
1 files changed, 0 insertions, 3349 deletions
diff --git a/src/fs/fs_api.c b/src/fs/fs_api.c
deleted file mode 100644
index 63b17a93e..000000000
--- a/src/fs/fs_api.c
+++ /dev/null
@@ -1,3349 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--2012 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_api.c
23 * @brief main FS functions (master initialization, serialization, deserialization, shared code)
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_fs_service.h"
30#include "fs_api.h"
31#include "fs_tree.h"
32
33/**
34 * How many block requests can we have outstanding in parallel at a time by default?
35 */
36#define DEFAULT_MAX_PARALLEL_REQUESTS (1024 * 10)
37
38/**
39 * How many downloads can we have outstanding in parallel at a time by default?
40 */
41#define DEFAULT_MAX_PARALLEL_DOWNLOADS 16
42
43/**
44 * Start the given job (send signal, remove from pending queue, update
45 * counters and state).
46 *
47 * @param qe job to start
48 */
49static void
50start_job (struct GNUNET_FS_QueueEntry *qe)
51{
52 qe->active = GNUNET_YES;
53 qe->start (qe->cls);
54 qe->start_times++;
55 qe->h->active_blocks += qe->blocks;
56 qe->h->active_downloads++;
57 qe->start_time = GNUNET_TIME_absolute_get ();
58 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
59 "Starting job %p (%u active)\n",
60 qe,
61 qe->h->active_downloads);
62 GNUNET_CONTAINER_DLL_remove (qe->h->pending_head, qe->h->pending_tail, qe);
63 GNUNET_CONTAINER_DLL_insert_after (qe->h->running_head,
64 qe->h->running_tail,
65 qe->h->running_tail,
66 qe);
67}
68
69
70/**
71 * Stop the given job (send signal, remove from active queue, update
72 * counters and state).
73 *
74 * @param qe job to stop
75 */
76static void
77stop_job (struct GNUNET_FS_QueueEntry *qe)
78{
79 qe->active = GNUNET_NO;
80 qe->stop (qe->cls);
81 GNUNET_assert (0 < qe->h->active_downloads);
82 qe->h->active_downloads--;
83 qe->h->active_blocks -= qe->blocks;
84 qe->run_time = GNUNET_TIME_relative_add (qe->run_time,
85 GNUNET_TIME_absolute_get_duration (
86 qe->start_time));
87 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
88 "Stopping job %p (%u active)\n",
89 qe,
90 qe->h->active_downloads);
91 GNUNET_CONTAINER_DLL_remove (qe->h->running_head, qe->h->running_tail, qe);
92 GNUNET_CONTAINER_DLL_insert_after (qe->h->pending_head,
93 qe->h->pending_tail,
94 qe->h->pending_tail,
95 qe);
96}
97
98
99/**
100 * Process the jobs in the job queue, possibly starting some
101 * and stopping others.
102 *
103 * @param cls the `struct GNUNET_FS_Handle *`
104 */
105static void
106process_job_queue (void *cls)
107{
108 struct GNUNET_FS_Handle *h = cls;
109 struct GNUNET_FS_QueueEntry *qe;
110 struct GNUNET_FS_QueueEntry *next;
111 struct GNUNET_TIME_Relative run_time;
112 struct GNUNET_TIME_Relative restart_at;
113 struct GNUNET_TIME_Relative rst;
114 struct GNUNET_TIME_Absolute end_time;
115 unsigned int num_downloads_waiting;
116 unsigned int num_downloads_active;
117 unsigned int num_downloads_expired;
118 unsigned int num_probes_active;
119 unsigned int num_probes_waiting;
120 unsigned int num_probes_expired;
121 int num_probes_change;
122 int num_downloads_change;
123 int block_limit_hit;
124
125 h->queue_job = NULL;
126 /* restart_at will be set to the time when it makes sense to
127 re-evaluate the job queue (unless, of course, jobs complete
128 or are added, then we'll be triggered immediately */
129 restart_at = GNUNET_TIME_UNIT_FOREVER_REL;
130 /* first, calculate some basic statistics on pending jobs */
131 num_probes_waiting = 0;
132 num_downloads_waiting = 0;
133 for (qe = h->pending_head; NULL != qe; qe = qe->next)
134 {
135 switch (qe->priority)
136 {
137 case GNUNET_FS_QUEUE_PRIORITY_PROBE:
138 num_probes_waiting++;
139 break;
140
141 case GNUNET_FS_QUEUE_PRIORITY_NORMAL:
142 num_downloads_waiting++;
143 break;
144
145 default:
146 GNUNET_break (0);
147 break;
148 }
149 }
150 /* now, calculate some basic statistics on running jobs */
151 num_probes_active = 0;
152 num_probes_expired = 0;
153 num_downloads_active = 0;
154 num_downloads_expired = 0;
155 next = h->running_head;
156 while (NULL != (qe = next))
157 {
158 next = qe->next;
159 switch (qe->priority)
160 {
161 case GNUNET_FS_QUEUE_PRIORITY_PROBE:
162 run_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2);
163 end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time);
164 rst = GNUNET_TIME_absolute_get_remaining (end_time);
165 if (0 == rst.rel_value_us)
166 {
167 num_probes_expired++;
168 stop_job (qe);
169 }
170 else
171 {
172 num_probes_active++;
173 restart_at = GNUNET_TIME_relative_min (rst, restart_at);
174 }
175 break;
176
177 case GNUNET_FS_QUEUE_PRIORITY_NORMAL:
178 run_time =
179 GNUNET_TIME_relative_saturating_multiply (h->avg_block_latency,
180 qe->blocks * qe->start_times);
181 end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time);
182 rst = GNUNET_TIME_absolute_get_remaining (end_time);
183 if (0 == rst.rel_value_us)
184 {
185 num_downloads_expired++;
186 stop_job (qe);
187 }
188 else
189 {
190 num_downloads_active++;
191 restart_at = GNUNET_TIME_relative_min (rst, restart_at);
192 }
193 break;
194
195 default:
196 GNUNET_break (0);
197 break;
198 }
199 }
200 GNUNET_break (h->active_downloads ==
201 num_downloads_active + num_probes_active);
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
203 "PA: %u, PE: %u, PW: %u; DA: %u, DE: %u, DW: %u\n",
204 num_probes_active,
205 num_probes_expired,
206 num_probes_waiting,
207 num_downloads_active,
208 num_downloads_expired,
209 num_downloads_waiting);
210 GNUNET_break (h->active_downloads + num_probes_active <=
211 h->max_parallel_downloads);
212 /* calculate start/stop decisions */
213 if (h->active_downloads + num_downloads_waiting > h->max_parallel_downloads)
214 {
215 /* stop as many probes as there are downloads and probes */
216 num_probes_change = -GNUNET_MIN (num_probes_active, num_downloads_waiting);
217 /* start as many downloads as there are free slots, including those
218 we just opened up */
219 num_downloads_change =
220 h->max_parallel_downloads - h->active_downloads - num_probes_change;
221 }
222 else
223 {
224 /* start all downloads (we can) */
225 num_downloads_change = num_downloads_waiting;
226 /* also start probes if there is room, but use a lower cap of (mpd/4) + 1 */
227 if (1 + h->max_parallel_downloads / 4 >=
228 (h->active_downloads + num_downloads_change))
229 num_probes_change =
230 GNUNET_MIN (num_probes_waiting,
231 (1 + h->max_parallel_downloads / 4)
232 - (h->active_downloads + num_downloads_change));
233 else
234 num_probes_change = 0;
235 }
236 GNUNET_break (num_downloads_change <= num_downloads_waiting);
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238 "Changing %d probes and %d/%u/%u downloads\n",
239 num_probes_change,
240 num_downloads_change,
241 (unsigned int) h->active_downloads,
242 (unsigned int) h->max_parallel_downloads);
243 /* actually stop probes */
244 next = h->running_head;
245 while (NULL != (qe = next))
246 {
247 next = qe->next;
248 if (GNUNET_FS_QUEUE_PRIORITY_PROBE != qe->priority)
249 continue;
250 if (num_probes_change < 0)
251 {
252 stop_job (qe);
253 num_probes_change++;
254 if (0 == num_probes_change)
255 break;
256 }
257 }
258 GNUNET_break (0 <= num_probes_change);
259
260 /* start some more tasks if we now have empty slots */
261 block_limit_hit = GNUNET_NO;
262 next = h->pending_head;
263 while ((NULL != (qe = next)) &&
264 ((num_probes_change > 0) || (num_downloads_change > 0)))
265 {
266 next = qe->next;
267 switch (qe->priority)
268 {
269 case GNUNET_FS_QUEUE_PRIORITY_PROBE:
270 if (num_probes_change > 0)
271 {
272 start_job (qe);
273 num_probes_change--;
274 run_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2);
275 restart_at = GNUNET_TIME_relative_min (run_time, restart_at);
276 }
277 break;
278
279 case GNUNET_FS_QUEUE_PRIORITY_NORMAL:
280 if ((num_downloads_change > 0) &&
281 ((qe->blocks + h->active_blocks <= h->max_parallel_requests) ||
282 ((qe->blocks > h->max_parallel_requests) &&
283 (0 == h->active_downloads))))
284 {
285 start_job (qe);
286 num_downloads_change--;
287 }
288 else if (num_downloads_change > 0)
289 block_limit_hit = GNUNET_YES;
290 break;
291
292 default:
293 GNUNET_break (0);
294 break;
295 }
296 }
297 GNUNET_break ((0 == num_downloads_change) || (GNUNET_YES == block_limit_hit));
298 GNUNET_break (0 == num_probes_change);
299
300 GNUNET_log (
301 GNUNET_ERROR_TYPE_DEBUG,
302 "AD: %u, MP: %u; %d probes and %d downloads to start, will run again in %s\n",
303 h->active_downloads,
304 h->max_parallel_requests,
305 num_probes_change,
306 num_downloads_change,
307 GNUNET_STRINGS_relative_time_to_string (restart_at, GNUNET_YES));
308
309 /* make sure we run again, callbacks might have
310 already re-scheduled the job, so cancel such
311 an operation (if it exists) */
312 if (NULL != h->queue_job)
313 GNUNET_SCHEDULER_cancel (h->queue_job);
314 h->queue_job =
315 GNUNET_SCHEDULER_add_delayed (restart_at, &process_job_queue, h);
316}
317
318
319/**
320 * Add a job to the queue.
321 *
322 * @param h handle to the overall FS state
323 * @param start function to call to begin the job
324 * @param stop function to call to pause the job, or on dequeue (if the job was running)
325 * @param cls closure for start and stop
326 * @param blocks number of blocks this jobs uses
327 * @param priority how important is this download
328 * @return queue handle
329 */
330struct GNUNET_FS_QueueEntry *
331GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h,
332 GNUNET_SCHEDULER_TaskCallback start,
333 GNUNET_SCHEDULER_TaskCallback stop,
334 void *cls,
335 unsigned int blocks,
336 enum GNUNET_FS_QueuePriority priority)
337{
338 struct GNUNET_FS_QueueEntry *qe;
339
340 qe = GNUNET_new (struct GNUNET_FS_QueueEntry);
341 qe->h = h;
342 qe->start = start;
343 qe->stop = stop;
344 qe->cls = cls;
345 qe->queue_time = GNUNET_TIME_absolute_get ();
346 qe->blocks = blocks;
347 qe->priority = priority;
348 GNUNET_CONTAINER_DLL_insert_after (h->pending_head,
349 h->pending_tail,
350 h->pending_tail,
351 qe);
352 if (NULL != h->queue_job)
353 GNUNET_SCHEDULER_cancel (h->queue_job);
354 h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h);
355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing job %p\n", qe);
356 return qe;
357}
358
359
360/**
361 * Dequeue a job from the queue.
362 *
363 * @param qe handle for the job
364 */
365void
366GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qe)
367{
368 struct GNUNET_FS_Handle *h;
369
370 h = qe->h;
371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dequeueing job %p\n", qe);
372 if (GNUNET_YES == qe->active)
373 stop_job (qe);
374 GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, qe);
375 GNUNET_free (qe);
376 if (NULL != h->queue_job)
377 GNUNET_SCHEDULER_cancel (h->queue_job);
378 h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h);
379}
380
381
382/**
383 * Create a top-level activity entry.
384 *
385 * @param h global fs handle
386 * @param ssf suspend signal function to use
387 * @param ssf_cls closure for @a ssf
388 * @return fresh top-level activity handle
389 */
390struct TopLevelActivity *
391GNUNET_FS_make_top (struct GNUNET_FS_Handle *h,
392 SuspendSignalFunction ssf,
393 void *ssf_cls)
394{
395 struct TopLevelActivity *ret;
396
397 ret = GNUNET_new (struct TopLevelActivity);
398 ret->ssf = ssf;
399 ret->ssf_cls = ssf_cls;
400 GNUNET_CONTAINER_DLL_insert (h->top_head, h->top_tail, ret);
401 return ret;
402}
403
404
405/**
406 * Destroy a top-level activity entry.
407 *
408 * @param h global fs handle
409 * @param top top level activity entry
410 */
411void
412GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, struct TopLevelActivity *top)
413{
414 GNUNET_CONTAINER_DLL_remove (h->top_head, h->top_tail, top);
415 GNUNET_free (top);
416}
417
418
419/**
420 * Closure for #GNUNET_FS_data_reader_file_().
421 */
422struct FileInfo
423{
424 /**
425 * Name of the file to read.
426 */
427 char *filename;
428
429 /**
430 * File descriptor, NULL if it has not yet been opened.
431 */
432 struct GNUNET_DISK_FileHandle *fd;
433};
434
435
436/**
437 * Function that provides data by reading from a file.
438 *
439 * @param cls closure with the `struct FileInfo *`
440 * @param offset offset to read from; it is possible
441 * that the caller might need to go backwards
442 * a bit at times; set to `UINT64_MAX` to tell
443 * the reader that we won't be reading for a while
444 * (used to close the file descriptor but NOT fully
445 * clean up the reader's state); in this case,
446 * a value of '0' for @a max should be ignored
447 * @param max maximum number of bytes that should be
448 * copied to @a buf; readers are not allowed
449 * to provide less data unless there is an error;
450 * a value of "0" will be used at the end to allow
451 * the reader to clean up its internal state
452 * @param buf where the reader should write the data
453 * @param emsg location for the reader to store an error message
454 * @return number of bytes written, usually @a max, 0 on error
455 */
456size_t
457GNUNET_FS_data_reader_file_ (void *cls,
458 uint64_t offset,
459 size_t max,
460 void *buf,
461 char **emsg)
462{
463 struct FileInfo *fi = cls;
464 ssize_t ret;
465
466 if (UINT64_MAX == offset)
467 {
468 if (NULL != fi->fd)
469 {
470 GNUNET_DISK_file_close (fi->fd);
471 fi->fd = NULL;
472 }
473 return 0;
474 }
475 if (0 == max)
476 {
477 if (NULL != fi->fd)
478 GNUNET_DISK_file_close (fi->fd);
479 GNUNET_free (fi->filename);
480 GNUNET_free (fi);
481 return 0;
482 }
483 if (NULL == fi->fd)
484 {
485 fi->fd = GNUNET_DISK_file_open (fi->filename,
486 GNUNET_DISK_OPEN_READ,
487 GNUNET_DISK_PERM_NONE);
488 if (NULL == fi->fd)
489 {
490 GNUNET_asprintf (emsg,
491 _ ("Could not open file `%s': %s"),
492 fi->filename,
493 strerror (errno));
494 return 0;
495 }
496 }
497 if ((GNUNET_SYSERR ==
498 GNUNET_DISK_file_seek (fi->fd, offset, GNUNET_DISK_SEEK_SET)) ||
499 (-1 == (ret = GNUNET_DISK_file_read (fi->fd, buf, max))))
500 {
501 GNUNET_asprintf (emsg,
502 _ ("Could not read file `%s': %s"),
503 fi->filename,
504 strerror (errno));
505 return 0;
506 }
507 if (ret != max)
508 {
509 GNUNET_asprintf (emsg,
510 _ ("Short read reading from file `%s'!"),
511 fi->filename);
512 return 0;
513 }
514 return max;
515}
516
517
518/**
519 * Create the closure for the #GNUNET_FS_data_reader_file_() callback.
520 *
521 * @param filename file to read
522 * @return closure to use, NULL on error
523 */
524void *
525GNUNET_FS_make_file_reader_context_ (const char *filename)
526{
527 struct FileInfo *fi;
528
529 fi = GNUNET_new (struct FileInfo);
530 fi->filename = GNUNET_STRINGS_filename_expand (filename);
531 if (NULL == fi->filename)
532 {
533 GNUNET_free (fi);
534 return NULL;
535 }
536 return fi;
537}
538
539
540/**
541 * Function that provides data by copying from a buffer.
542 *
543 * @param cls closure (points to the buffer)
544 * @param offset offset to read from; it is possible
545 * that the caller might need to go backwards
546 * a bit at times; set to `UINT64_MAX` to tell
547 * the reader that we won't be reading for a while
548 * (used to close the file descriptor but NOT fully
549 * clean up the reader's state); in this case,
550 * a value of '0' for @a max should be ignored
551 * @param max maximum number of bytes that should be
552 * copied to @a buf; readers are not allowed
553 * to provide less data unless there is an error;
554 * a value of "0" will be used at the end to allow
555 * the reader to clean up its internal state
556 * @param buf where the reader should write the data
557 * @param emsg location for the reader to store an error message
558 * @return number of bytes written, usually @a max, 0 on error
559 */
560size_t
561GNUNET_FS_data_reader_copy_ (void *cls,
562 uint64_t offset,
563 size_t max,
564 void *buf,
565 char **emsg)
566{
567 char *data = cls;
568
569 if (UINT64_MAX == offset)
570 return 0;
571 if (0 == max)
572 {
573 GNUNET_free (data);
574 return 0;
575 }
576 GNUNET_memcpy (buf, &data[offset], max);
577 return max;
578}
579
580
581/**
582 * Return the full filename where we would store state information
583 * (for serialization/deserialization).
584 *
585 * @param h master context
586 * @param ext component of the path
587 * @param ent entity identifier (or empty string for the directory)
588 * @return NULL on error
589 */
590static char *
591get_serialization_file_name (struct GNUNET_FS_Handle *h,
592 const char *ext,
593 const char *ent)
594{
595 char *basename;
596 char *ret;
597
598 if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
599 return NULL; /* persistence not requested */
600 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg,
601 "fs",
602 "STATE_DIR",
603 &basename))
604 return NULL;
605 GNUNET_asprintf (&ret,
606 "%s%s%s%s%s%s%s",
607 basename,
608 DIR_SEPARATOR_STR,
609 h->client_name,
610 DIR_SEPARATOR_STR,
611 ext,
612 DIR_SEPARATOR_STR,
613 ent);
614 GNUNET_free (basename);
615 return ret;
616}
617
618
619/**
620 * Return the full filename where we would store state information
621 * (for serialization/deserialization) that is associated with a
622 * parent operation.
623 *
624 * @param h master context
625 * @param ext component of the path
626 * @param uni name of the parent operation
627 * @param ent entity identifier (or empty string for the directory)
628 * @return NULL on error
629 */
630static char *
631get_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h,
632 const char *ext,
633 const char *uni,
634 const char *ent)
635{
636 char *basename;
637 char *ret;
638
639 if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
640 return NULL; /* persistence not requested */
641 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg,
642 "fs",
643 "STATE_DIR",
644 &basename))
645 return NULL;
646 GNUNET_asprintf (&ret,
647 "%s%s%s%s%s%s%s.dir%s%s",
648 basename,
649 DIR_SEPARATOR_STR,
650 h->client_name,
651 DIR_SEPARATOR_STR,
652 ext,
653 DIR_SEPARATOR_STR,
654 uni,
655 DIR_SEPARATOR_STR,
656 ent);
657 GNUNET_free (basename);
658 return ret;
659}
660
661
662/**
663 * Return a read handle for deserialization.
664 *
665 * @param h master context
666 * @param ext component of the path
667 * @param ent entity identifier (or empty string for the directory)
668 * @return NULL on error
669 */
670static struct GNUNET_BIO_ReadHandle *
671get_read_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent)
672{
673 char *fn;
674 struct GNUNET_BIO_ReadHandle *ret;
675
676 fn = get_serialization_file_name (h, ext, ent);
677 if (NULL == fn)
678 return NULL;
679 ret = GNUNET_BIO_read_open_file (fn);
680 GNUNET_free (fn);
681 return ret;
682}
683
684
685/**
686 * Return a write handle for serialization.
687 *
688 * @param h master context
689 * @param ext component of the path
690 * @param ent entity identifier (or empty string for the directory)
691 * @return NULL on error
692 */
693static struct GNUNET_BIO_WriteHandle *
694get_write_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent)
695{
696 char *fn;
697 struct GNUNET_BIO_WriteHandle *ret;
698
699 fn = get_serialization_file_name (h, ext, ent);
700 if (NULL == fn)
701 return NULL;
702 ret = GNUNET_BIO_write_open_file (fn);
703 GNUNET_break (NULL != ret);
704 GNUNET_free (fn);
705 return ret;
706}
707
708
709/**
710 * Return a write handle for serialization.
711 *
712 * @param h master context
713 * @param ext component of the path
714 * @param uni name of parent
715 * @param ent entity identifier (or empty string for the directory)
716 * @return NULL on error
717 */
718static struct GNUNET_BIO_WriteHandle *
719get_write_handle_in_dir (struct GNUNET_FS_Handle *h,
720 const char *ext,
721 const char *uni,
722 const char *ent)
723{
724 char *fn;
725 struct GNUNET_BIO_WriteHandle *ret;
726
727 fn = get_serialization_file_name_in_dir (h, ext, uni, ent);
728 if (NULL == fn)
729 return NULL;
730 ret = GNUNET_BIO_write_open_file (fn);
731 GNUNET_free (fn);
732 return ret;
733}
734
735
736/**
737 * Remove serialization/deserialization file from disk.
738 *
739 * @param h master context
740 * @param ext component of the path
741 * @param ent entity identifier
742 */
743void
744GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h,
745 const char *ext,
746 const char *ent)
747{
748 char *filename;
749
750 if ((NULL == ent) || (0 == strlen (ent)))
751 {
752 GNUNET_break (0);
753 return;
754 }
755 filename = get_serialization_file_name (h, ext, ent);
756 if (NULL != filename)
757 {
758 if ((0 != unlink (filename)) && (ENOENT != errno))
759 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
760 GNUNET_free (filename);
761 }
762}
763
764
765/**
766 * Remove serialization/deserialization file from disk.
767 *
768 * @param h master context
769 * @param ext component of the path
770 * @param uni parent name
771 * @param ent entity identifier
772 */
773static void
774remove_sync_file_in_dir (struct GNUNET_FS_Handle *h,
775 const char *ext,
776 const char *uni,
777 const char *ent)
778{
779 char *filename;
780
781 if ((NULL == ent) || (0 == strlen (ent)))
782 {
783 GNUNET_break (0);
784 return;
785 }
786 filename = get_serialization_file_name_in_dir (h, ext, uni, ent);
787 if (NULL == filename)
788 return;
789 if (0 != unlink (filename))
790 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
791 GNUNET_free (filename);
792}
793
794
795/**
796 * Remove serialization/deserialization directory from disk.
797 *
798 * @param h master context
799 * @param ext component of the path
800 * @param uni unique name of parent
801 */
802void
803GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h,
804 const char *ext,
805 const char *uni)
806{
807 char *dn;
808
809 if (NULL == uni)
810 return;
811 dn = get_serialization_file_name_in_dir (h, ext, uni, "");
812 if (NULL == dn)
813 return;
814 if ((GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) &&
815 (GNUNET_OK != GNUNET_DISK_directory_remove (dn)))
816 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dn);
817 GNUNET_free (dn);
818}
819
820
821/**
822 * Serialize a start-time. Since we use start-times to
823 * calculate the duration of some operation, we actually
824 * do not serialize the absolute time but the (relative)
825 * duration since the start time. When we then
826 * deserialize the start time, we take the current time and
827 * subtract that duration so that we get again an absolute
828 * time stamp that will result in correct performance
829 * calculations.
830 *
831 * @param wh handle for writing
832 * @param timestamp time to serialize
833 * @return #GNUNET_OK on success
834 */
835static int
836write_start_time (struct GNUNET_BIO_WriteHandle *wh,
837 struct GNUNET_TIME_Absolute timestamp)
838{
839 struct GNUNET_TIME_Relative dur;
840
841 dur = GNUNET_TIME_absolute_get_duration (timestamp);
842 return GNUNET_BIO_write_int64 (wh, "start time", dur.rel_value_us);
843}
844
845
846/**
847 * Deserialize a start-time. Since we use start-times to
848 * calculate the duration of some operation, we actually
849 * do not serialize the absolute time but the (relative)
850 * duration since the start time. Thus, when we then
851 * deserialize the start time, we take the current time and
852 * subtract that duration so that we get again an absolute
853 * time stamp that will result in correct performance
854 * calculations.
855 *
856 * @param rh handle for reading
857 * @param timestamp where to write the deserialized timestamp
858 * @return #GNUNET_OK on success
859 */
860static int
861read_start_time (struct GNUNET_BIO_ReadHandle *rh,
862 struct GNUNET_TIME_Absolute *timestamp)
863{
864 struct GNUNET_TIME_Relative dur;
865
866 if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, "start time",
867 (int64_t *) &dur.rel_value_us))
868 return GNUNET_SYSERR;
869 *timestamp = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), dur);
870 return GNUNET_OK;
871}
872
873
874/**
875 * Using the given serialization filename, try to deserialize
876 * the file-information tree associated with it.
877 *
878 * @param h master context
879 * @param filename name of the file (without directory) with
880 * the information
881 * @return NULL on error
882 */
883static struct GNUNET_FS_FileInformation *
884deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename);
885
886
887/**
888 * Using the given serialization filename, try to deserialize
889 * the file-information tree associated with it.
890 *
891 * @param h master context
892 * @param fn name of the file (without directory) with
893 * the information
894 * @param rh handle for reading
895 * @return NULL on error
896 */
897static struct GNUNET_FS_FileInformation *
898deserialize_fi_node (struct GNUNET_FS_Handle *h,
899 const char *fn,
900 struct GNUNET_BIO_ReadHandle *rh)
901{
902 struct GNUNET_FS_FileInformation *ret;
903 struct GNUNET_FS_FileInformation *nxt;
904 char b;
905 char *ksks;
906 char *chks;
907 char *skss;
908 char *filename;
909 uint32_t dsize;
910
911 if (GNUNET_OK != GNUNET_BIO_read (rh, "status flag", &b, sizeof(b)))
912 {
913 GNUNET_break (0);
914 return NULL;
915 }
916 ret = GNUNET_new (struct GNUNET_FS_FileInformation);
917 ret->h = h;
918 ksks = NULL;
919 chks = NULL;
920 skss = NULL;
921 filename = NULL;
922 if ((GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "metadata", &ret->meta)) ||
923 (GNUNET_OK != GNUNET_BIO_read_string (rh, "ksk-uri", &ksks, 32 * 1024)) ||
924 ((NULL != ksks) &&
925 ((NULL == (ret->keywords = GNUNET_FS_uri_parse (ksks, NULL))) ||
926 (GNUNET_YES != GNUNET_FS_uri_test_ksk (ret->keywords)))) ||
927 (GNUNET_OK != GNUNET_BIO_read_string (rh, "chk-uri", &chks, 1024)) ||
928 ((NULL != chks) &&
929 ((NULL == (ret->chk_uri = GNUNET_FS_uri_parse (chks, NULL))) ||
930 (GNUNET_YES != GNUNET_FS_uri_test_chk (ret->chk_uri)))) ||
931 (GNUNET_OK != GNUNET_BIO_read_string (rh, "sks-uri", &skss, 1024)) ||
932 ((NULL != skss) &&
933 ((NULL == (ret->sks_uri = GNUNET_FS_uri_parse (skss, NULL))) ||
934 (GNUNET_YES != GNUNET_FS_uri_test_sks (ret->sks_uri)))) ||
935 (GNUNET_OK != read_start_time (rh, &ret->start_time)) ||
936 (GNUNET_OK !=
937 GNUNET_BIO_read_string (rh, "emsg", &ret->emsg, 16 * 1024)) ||
938 (GNUNET_OK !=
939 GNUNET_BIO_read_string (rh, "fn", &ret->filename, 16 * 1024)) ||
940 (GNUNET_OK !=
941 GNUNET_BIO_read_int64 (
942 rh,
943 "expiration time",
944 (int64_t *) &ret->bo.expiration_time.abs_value_us)) ||
945 (GNUNET_OK != GNUNET_BIO_read_int32 (
946 rh,
947 "anonymity level",
948 (int32_t *) &ret->bo.anonymity_level)) ||
949 (GNUNET_OK != GNUNET_BIO_read_int32 (
950 rh,
951 "content priority",
952 (int32_t *) &ret->bo.content_priority)) ||
953 (GNUNET_OK != GNUNET_BIO_read_int32 (
954 rh,
955 "replication level",
956 (int32_t *) &ret->bo.replication_level)))
957 {
958 GNUNET_break (0);
959 goto cleanup;
960 }
961 switch (b)
962 {
963 case 0: /* file-insert */
964 if (GNUNET_OK != GNUNET_BIO_read_int64 (
965 rh,
966 "file size",
967 (int64_t *) &ret->data.file.file_size))
968 {
969 GNUNET_break (0);
970 goto cleanup;
971 }
972 ret->is_directory = GNUNET_NO;
973 ret->data.file.do_index = GNUNET_NO;
974 ret->data.file.have_hash = GNUNET_NO;
975 ret->data.file.index_start_confirmed = GNUNET_NO;
976 if (GNUNET_NO == ret->is_published)
977 {
978 if (NULL == ret->filename)
979 {
980 ret->data.file.reader = &GNUNET_FS_data_reader_copy_;
981 ret->data.file.reader_cls =
982 GNUNET_malloc_large (ret->data.file.file_size);
983 if (ret->data.file.reader_cls == NULL)
984 goto cleanup;
985 if (GNUNET_OK != GNUNET_BIO_read (rh,
986 "file-data",
987 ret->data.file.reader_cls,
988 ret->data.file.file_size))
989 {
990 GNUNET_break (0);
991 goto cleanup;
992 }
993 }
994 else
995 {
996 ret->data.file.reader = &GNUNET_FS_data_reader_file_;
997 ret->data.file.reader_cls =
998 GNUNET_FS_make_file_reader_context_ (ret->filename);
999 }
1000 }
1001 break;
1002
1003 case 1: /* file-index, no hash */
1004 if (NULL == ret->filename)
1005 {
1006 GNUNET_break (0);
1007 goto cleanup;
1008 }
1009 if (GNUNET_OK != GNUNET_BIO_read_int64 (
1010 rh,
1011 "file size",
1012 (int64_t *) &ret->data.file.file_size))
1013 {
1014 GNUNET_break (0);
1015 goto cleanup;
1016 }
1017 ret->is_directory = GNUNET_NO;
1018 ret->data.file.do_index = GNUNET_YES;
1019 ret->data.file.have_hash = GNUNET_NO;
1020 ret->data.file.index_start_confirmed = GNUNET_NO;
1021 ret->data.file.reader = &GNUNET_FS_data_reader_file_;
1022 ret->data.file.reader_cls =
1023 GNUNET_FS_make_file_reader_context_ (ret->filename);
1024 break;
1025
1026 case 2: /* file-index-with-hash */
1027 if (NULL == ret->filename)
1028 {
1029 GNUNET_break (0);
1030 goto cleanup;
1031 }
1032 if ((GNUNET_OK != GNUNET_BIO_read_int64 (
1033 rh,
1034 "file size",
1035 (int64_t *) &ret->data.file.file_size)) ||
1036 (GNUNET_OK != GNUNET_BIO_read (rh,
1037 "fileid",
1038 &ret->data.file.file_id,
1039 sizeof(struct GNUNET_HashCode))))
1040 {
1041 GNUNET_break (0);
1042 goto cleanup;
1043 }
1044 ret->is_directory = GNUNET_NO;
1045 ret->data.file.do_index = GNUNET_YES;
1046 ret->data.file.have_hash = GNUNET_YES;
1047 ret->data.file.index_start_confirmed = GNUNET_NO;
1048 ret->data.file.reader = &GNUNET_FS_data_reader_file_;
1049 ret->data.file.reader_cls =
1050 GNUNET_FS_make_file_reader_context_ (ret->filename);
1051 break;
1052
1053 case 3: /* file-index-with-hash-confirmed */
1054 if (NULL == ret->filename)
1055 {
1056 GNUNET_break (0);
1057 goto cleanup;
1058 }
1059 if ((GNUNET_OK != GNUNET_BIO_read_int64 (
1060 rh,
1061 "file size",
1062 (int64_t *) &ret->data.file.file_size)) ||
1063 (GNUNET_OK != GNUNET_BIO_read (rh,
1064 "fileid",
1065 &ret->data.file.file_id,
1066 sizeof(struct GNUNET_HashCode))))
1067 {
1068 GNUNET_break (0);
1069 goto cleanup;
1070 }
1071 ret->is_directory = GNUNET_NO;
1072 ret->data.file.do_index = GNUNET_YES;
1073 ret->data.file.have_hash = GNUNET_YES;
1074 ret->data.file.index_start_confirmed = GNUNET_YES;
1075 ret->data.file.reader = &GNUNET_FS_data_reader_file_;
1076 ret->data.file.reader_cls =
1077 GNUNET_FS_make_file_reader_context_ (ret->filename);
1078 break;
1079
1080 case 4: /* directory */
1081 ret->is_directory = GNUNET_YES;
1082 if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, "dsize",
1083 (int32_t *) &dsize)) ||
1084 (GNUNET_OK !=
1085 GNUNET_BIO_read_int64 (
1086 rh,
1087 "contents completed",
1088 (int64_t *) &ret->data.dir.contents_completed)) ||
1089 (GNUNET_OK !=
1090 GNUNET_BIO_read_int64 (
1091 rh,
1092 "contents size",
1093 (int64_t *) &ret->data.dir.contents_size)) ||
1094 (NULL == (ret->data.dir.dir_data = GNUNET_malloc_large (dsize))) ||
1095 (GNUNET_OK !=
1096 GNUNET_BIO_read (rh, "dir-data", ret->data.dir.dir_data, dsize)) ||
1097 (GNUNET_OK !=
1098 GNUNET_BIO_read_string (rh, "ent-filename", &filename, 16 * 1024)))
1099 {
1100 GNUNET_break (0);
1101 goto cleanup;
1102 }
1103 ret->data.dir.dir_size = (uint32_t) dsize;
1104 if (NULL != filename)
1105 {
1106 ret->data.dir.entries = deserialize_file_information (h, filename);
1107 GNUNET_free (filename);
1108 filename = NULL;
1109 nxt = ret->data.dir.entries;
1110 while (NULL != nxt)
1111 {
1112 nxt->dir = ret;
1113 nxt = nxt->next;
1114 }
1115 }
1116 break;
1117
1118 default:
1119 GNUNET_break (0);
1120 goto cleanup;
1121 }
1122 ret->serialization = GNUNET_strdup (fn);
1123 if (GNUNET_OK !=
1124 GNUNET_BIO_read_string (rh, "nxt-filename", &filename, 16 * 1024))
1125 {
1126 GNUNET_break (0);
1127 goto cleanup;
1128 }
1129 if (NULL != filename)
1130 {
1131 ret->next = deserialize_file_information (h, filename);
1132 GNUNET_free (filename);
1133 filename = NULL;
1134 }
1135 GNUNET_free (ksks);
1136 GNUNET_free (skss);
1137 GNUNET_free (chks);
1138 return ret;
1139cleanup:
1140 GNUNET_free (ksks);
1141 GNUNET_free (chks);
1142 GNUNET_free (skss);
1143 GNUNET_free (filename);
1144 GNUNET_FS_file_information_destroy (ret, NULL, NULL);
1145 return NULL;
1146}
1147
1148
1149/**
1150 * Using the given serialization filename, try to deserialize
1151 * the file-information tree associated with it.
1152 *
1153 * @param h master context
1154 * @param filename name of the file (without directory) with
1155 * the information
1156 * @return NULL on error
1157 */
1158static struct GNUNET_FS_FileInformation *
1159deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename)
1160{
1161 struct GNUNET_FS_FileInformation *ret;
1162 struct GNUNET_BIO_ReadHandle *rh;
1163 char *emsg;
1164 char *fn;
1165
1166 rh = get_read_handle (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename);
1167 if (NULL == rh)
1168 return NULL;
1169 ret = deserialize_fi_node (h, filename, rh);
1170 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
1171 {
1172 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1173 _ ("Failed to resume publishing information `%s': %s\n"),
1174 filename,
1175 emsg);
1176 GNUNET_free (emsg);
1177 }
1178 if (NULL == ret)
1179 {
1180 fn =
1181 get_serialization_file_name (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename);
1182 if (NULL != fn)
1183 {
1184 if (0 != unlink (fn))
1185 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
1186 GNUNET_free (fn);
1187 }
1188 }
1189 return ret;
1190}
1191
1192
1193/**
1194 * Given a serialization name (full absolute path), return the
1195 * basename of the file (without the path), which must only
1196 * consist of the 6 random characters.
1197 *
1198 * @param fullname name to extract the basename from
1199 * @return copy of the basename, NULL on error
1200 */
1201static char *
1202get_serialization_short_name (const char *fullname)
1203{
1204 const char *end;
1205 const char *nxt;
1206
1207 end = NULL;
1208 nxt = fullname;
1209 /* FIXME: we could do this faster since we know
1210 * the length of 'end'... */
1211 while ('\0' != *nxt)
1212 {
1213 if (DIR_SEPARATOR == *nxt)
1214 end = nxt + 1;
1215 nxt++;
1216 }
1217 if ((NULL == end) || (0 == strlen (end)))
1218 {
1219 GNUNET_break (0);
1220 return NULL;
1221 }
1222 GNUNET_break (6 == strlen (end));
1223 return GNUNET_strdup (end);
1224}
1225
1226
1227/**
1228 * Create a new random name for serialization. Also checks if persistence
1229 * is enabled and returns NULL if not.
1230 *
1231 * @param h master context
1232 * @param ext component of the path
1233 * @return NULL on error
1234 */
1235static char *
1236make_serialization_file_name (struct GNUNET_FS_Handle *h, const char *ext)
1237{
1238 char *fn;
1239 char *dn;
1240 char *ret;
1241
1242 if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
1243 return NULL; /* persistence not requested */
1244 dn = get_serialization_file_name (h, ext, "");
1245 if (NULL == dn)
1246 return NULL;
1247 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn))
1248 {
1249 GNUNET_free (dn);
1250 return NULL;
1251 }
1252 fn = GNUNET_DISK_mktemp (dn);
1253 GNUNET_free (dn);
1254 if (NULL == fn)
1255 return NULL; /* epic fail */
1256 ret = get_serialization_short_name (fn);
1257 GNUNET_free (fn);
1258 return ret;
1259}
1260
1261
1262/**
1263 * Create a new random name for serialization. Also checks if persistence
1264 * is enabled and returns NULL if not.
1265 *
1266 * @param h master context
1267 * @param ext component of the path
1268 * @param uni name of parent
1269 * @return NULL on error
1270 */
1271static char *
1272make_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h,
1273 const char *ext,
1274 const char *uni)
1275{
1276 char *fn;
1277 char *dn;
1278 char *ret;
1279
1280 if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
1281 return NULL; /* persistence not requested */
1282 dn = get_serialization_file_name_in_dir (h, ext, uni, "");
1283 if (NULL == dn)
1284 return NULL;
1285 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn))
1286 {
1287 GNUNET_free (dn);
1288 return NULL;
1289 }
1290 fn = GNUNET_DISK_mktemp (dn);
1291 GNUNET_free (dn);
1292 if (NULL == fn)
1293 return NULL; /* epic fail */
1294 ret = get_serialization_short_name (fn);
1295 GNUNET_free (fn);
1296 return ret;
1297}
1298
1299
1300/**
1301 * Copy all of the data from the reader to the write handle.
1302 *
1303 * @param wh write handle
1304 * @param fi file with reader
1305 * @return #GNUNET_OK on success
1306 */
1307static int
1308copy_from_reader (struct GNUNET_BIO_WriteHandle *wh,
1309 struct GNUNET_FS_FileInformation *fi)
1310{
1311 char buf[32 * 1024];
1312 uint64_t off;
1313 size_t ret;
1314 size_t left;
1315 char *emsg;
1316
1317 emsg = NULL;
1318 off = 0;
1319 while (off < fi->data.file.file_size)
1320 {
1321 left = GNUNET_MIN (sizeof(buf), fi->data.file.file_size - off);
1322 ret =
1323 fi->data.file.reader (fi->data.file.reader_cls, off, left, buf, &emsg);
1324 if (0 == ret)
1325 {
1326 GNUNET_free (emsg);
1327 return GNUNET_SYSERR;
1328 }
1329 if (GNUNET_OK != GNUNET_BIO_write (wh, "copied from reader", buf, ret))
1330 return GNUNET_SYSERR;
1331 off += ret;
1332 }
1333 return GNUNET_OK;
1334}
1335
1336
1337/**
1338 * Create a temporary file on disk to store the current
1339 * state of @a fi in.
1340 *
1341 * @param fi file information to sync with disk
1342 */
1343void
1344GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *fi)
1345{
1346 char *fn;
1347 struct GNUNET_BIO_WriteHandle *wh;
1348 char b;
1349 char *ksks;
1350 char *chks;
1351 char *skss;
1352
1353 if (NULL == fi->serialization)
1354 fi->serialization =
1355 make_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO);
1356 if (NULL == fi->serialization)
1357 return;
1358 wh =
1359 get_write_handle (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO, fi->serialization);
1360 if (NULL == wh)
1361 {
1362 GNUNET_free (fi->serialization);
1363 fi->serialization = NULL;
1364 return;
1365 }
1366 if (GNUNET_YES == fi->is_directory)
1367 b = 4;
1368 else if (GNUNET_YES == fi->data.file.index_start_confirmed)
1369 b = 3;
1370 else if (GNUNET_YES == fi->data.file.have_hash)
1371 b = 2;
1372 else if (GNUNET_YES == fi->data.file.do_index)
1373 b = 1;
1374 else
1375 b = 0;
1376 if (NULL != fi->keywords)
1377 ksks = GNUNET_FS_uri_to_string (fi->keywords);
1378 else
1379 ksks = NULL;
1380 if (NULL != fi->chk_uri)
1381 chks = GNUNET_FS_uri_to_string (fi->chk_uri);
1382 else
1383 chks = NULL;
1384 if (NULL != fi->sks_uri)
1385 skss = GNUNET_FS_uri_to_string (fi->sks_uri);
1386 else
1387 skss = NULL;
1388 struct GNUNET_BIO_WriteSpec ws1[] = {
1389 GNUNET_BIO_write_spec_object ("b", &b, sizeof (b)),
1390 GNUNET_BIO_write_spec_meta_data ("meta", fi->meta),
1391 GNUNET_BIO_write_spec_string ("ksks", ksks),
1392 GNUNET_BIO_write_spec_string ("chks", chks),
1393 GNUNET_BIO_write_spec_string ("skss", skss),
1394 GNUNET_BIO_write_spec_end (),
1395 };
1396 struct GNUNET_BIO_WriteSpec ws2[] = {
1397 GNUNET_BIO_write_spec_string ("emsg", fi->emsg),
1398 GNUNET_BIO_write_spec_string ("filename", fi->filename),
1399 GNUNET_BIO_write_spec_int64 (
1400 "expiration time",
1401 (int64_t *) &fi->bo.expiration_time.abs_value_us),
1402 GNUNET_BIO_write_spec_int32 (
1403 "anonymity level",
1404 (int32_t *) &fi->bo.anonymity_level),
1405 GNUNET_BIO_write_spec_int32 (
1406 "content priority",
1407 (int32_t *) &fi->bo.content_priority),
1408 GNUNET_BIO_write_spec_int32 (
1409 "replication level",
1410 (int32_t *) &fi->bo.replication_level),
1411 GNUNET_BIO_write_spec_end (),
1412 };
1413 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws1)) ||
1414 (GNUNET_OK != write_start_time (wh, fi->start_time)) ||
1415 (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws2)))
1416 {
1417 GNUNET_break (0);
1418 goto cleanup;
1419 }
1420 GNUNET_free (chks);
1421 chks = NULL;
1422 GNUNET_free (ksks);
1423 ksks = NULL;
1424 GNUNET_free (skss);
1425 skss = NULL;
1426
1427 switch (b)
1428 {
1429 case 0: /* file-insert */
1430 if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, "file size",
1431 fi->data.file.file_size))
1432 {
1433 GNUNET_break (0);
1434 goto cleanup;
1435 }
1436 if ((GNUNET_NO == fi->is_published) && (NULL == fi->filename))
1437 if (GNUNET_OK != copy_from_reader (wh, fi))
1438 {
1439 GNUNET_break (0);
1440 goto cleanup;
1441 }
1442 break;
1443
1444 case 1: /* file-index, no hash */
1445 if (NULL == fi->filename)
1446 {
1447 GNUNET_break (0);
1448 goto cleanup;
1449 }
1450 if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, "file size",
1451 fi->data.file.file_size))
1452 {
1453 GNUNET_break (0);
1454 goto cleanup;
1455 }
1456 break;
1457
1458 case 2: /* file-index-with-hash */
1459 case 3: /* file-index-with-hash-confirmed */
1460 if (NULL == fi->filename)
1461 {
1462 GNUNET_break (0);
1463 goto cleanup;
1464 }
1465 if ((GNUNET_OK != GNUNET_BIO_write_int64 (wh, "file size",
1466 fi->data.file.file_size)) ||
1467 (GNUNET_OK != GNUNET_BIO_write (wh,
1468 "file id",
1469 &fi->data.file.file_id,
1470 sizeof(struct GNUNET_HashCode))))
1471 {
1472 GNUNET_break (0);
1473 goto cleanup;
1474 }
1475 break;
1476
1477 case 4: /* directory */
1478 if ((NULL != fi->data.dir.entries) &&
1479 (NULL == fi->data.dir.entries->serialization))
1480 GNUNET_FS_file_information_sync_ (fi->data.dir.entries);
1481 struct GNUNET_BIO_WriteSpec ws[] = {
1482 GNUNET_BIO_write_spec_int32 ("dir size",
1483 (int32_t *) &fi->data.dir.dir_size),
1484 GNUNET_BIO_write_spec_int64 (
1485 "contents completed",
1486 (int64_t *) &fi->data.dir.contents_completed),
1487 GNUNET_BIO_write_spec_int64 ("contents size",
1488 (int64_t *) &fi->data.dir.contents_size),
1489 GNUNET_BIO_write_spec_object ("dir data",
1490 fi->data.dir.dir_data,
1491 (uint32_t) fi->data.dir.dir_size),
1492 GNUNET_BIO_write_spec_string ("dir entries",
1493 (fi->data.dir.entries == NULL)
1494 ? NULL
1495 : fi->data.dir.entries->serialization),
1496 GNUNET_BIO_write_spec_end (),
1497 };
1498 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)))
1499 {
1500 GNUNET_break (0);
1501 goto cleanup;
1502 }
1503 break;
1504
1505 default:
1506 GNUNET_assert (0);
1507 goto cleanup;
1508 }
1509 if ((NULL != fi->next) && (NULL == fi->next->serialization))
1510 GNUNET_FS_file_information_sync_ (fi->next);
1511 if (GNUNET_OK != GNUNET_BIO_write_string (wh,
1512 "serialization",
1513 (fi->next != NULL)
1514 ? fi->next->serialization
1515 : NULL))
1516 {
1517 GNUNET_break (0);
1518 goto cleanup;
1519 }
1520 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
1521 {
1522 wh = NULL;
1523 GNUNET_break (0);
1524 goto cleanup;
1525 }
1526 return; /* done! */
1527cleanup:
1528 if (NULL != wh)
1529 (void) GNUNET_BIO_write_close (wh, NULL);
1530 GNUNET_free (chks);
1531 GNUNET_free (ksks);
1532 GNUNET_free (skss);
1533 fn = get_serialization_file_name (fi->h,
1534 GNUNET_FS_SYNC_PATH_FILE_INFO,
1535 fi->serialization);
1536 if (NULL != fn)
1537 {
1538 if (0 != unlink (fn))
1539 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
1540 GNUNET_free (fn);
1541 }
1542 GNUNET_free (fi->serialization);
1543 fi->serialization = NULL;
1544}
1545
1546
1547/**
1548 * Find the entry in the file information struct where the
1549 * serialization filename matches the given name.
1550 *
1551 * @param pos file information to search
1552 * @param srch filename to search for
1553 * @return NULL if srch was not found in this subtree
1554 */
1555static struct GNUNET_FS_FileInformation *
1556find_file_position (struct GNUNET_FS_FileInformation *pos, const char *srch)
1557{
1558 struct GNUNET_FS_FileInformation *r;
1559
1560 while (NULL != pos)
1561 {
1562 if (0 == strcmp (srch, pos->serialization))
1563 return pos;
1564 if ((GNUNET_YES == pos->is_directory) &&
1565 (NULL != (r = find_file_position (pos->data.dir.entries, srch))))
1566 return r;
1567 pos = pos->next;
1568 }
1569 return NULL;
1570}
1571
1572
1573/**
1574 * Signal the FS's progress function that we are resuming
1575 * an upload.
1576 *
1577 * @param cls closure (of type `struct GNUNET_FS_PublishContext *`, for the parent (!))
1578 * @param fi the entry in the publish-structure
1579 * @param length length of the file or directory
1580 * @param meta metadata for the file or directory (can be modified)
1581 * @param uri pointer to the keywords that will be used for this entry (can be modified)
1582 * @param bo block options (can be modified)
1583 * @param do_index should we index?
1584 * @param client_info pointer to client context set upon creation (can be modified)
1585 * @return #GNUNET_OK to continue (always)
1586 */
1587static int
1588fip_signal_resume (void *cls,
1589 struct GNUNET_FS_FileInformation *fi,
1590 uint64_t length,
1591 struct GNUNET_CONTAINER_MetaData *meta,
1592 struct GNUNET_FS_Uri **uri,
1593 struct GNUNET_FS_BlockOptions *bo,
1594 int *do_index,
1595 void **client_info)
1596{
1597 struct GNUNET_FS_PublishContext *pc = cls;
1598 struct GNUNET_FS_ProgressInfo pi;
1599
1600 if (GNUNET_YES == pc->skip_next_fi_callback)
1601 {
1602 pc->skip_next_fi_callback = GNUNET_NO;
1603 return GNUNET_OK;
1604 }
1605 pi.status = GNUNET_FS_STATUS_PUBLISH_RESUME;
1606 pi.value.publish.specifics.resume.message = fi->emsg;
1607 pi.value.publish.specifics.resume.chk_uri = fi->chk_uri;
1608 *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0);
1609 if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta))
1610 {
1611 /* process entries in directory */
1612 pc->skip_next_fi_callback = GNUNET_YES;
1613 GNUNET_FS_file_information_inspect (fi, &fip_signal_resume, pc);
1614 }
1615 return GNUNET_OK;
1616}
1617
1618
1619/**
1620 * Function called with a filename of serialized publishing operation
1621 * to deserialize.
1622 *
1623 * @param cls the `struct GNUNET_FS_Handle *`
1624 * @param filename complete filename (absolute path)
1625 * @return #GNUNET_OK (continue to iterate)
1626 */
1627static int
1628deserialize_publish_file (void *cls, const char *filename)
1629{
1630 struct GNUNET_FS_Handle *h = cls;
1631 struct GNUNET_BIO_ReadHandle *rh;
1632 struct GNUNET_FS_PublishContext *pc;
1633 int32_t options;
1634 int32_t all_done;
1635 int32_t have_ns;
1636 char *fi_root;
1637 struct GNUNET_CRYPTO_EcdsaPrivateKey ns;
1638 char *fi_pos;
1639 char *emsg;
1640
1641 pc = GNUNET_new (struct GNUNET_FS_PublishContext);
1642 pc->h = h;
1643 pc->serialization = get_serialization_short_name (filename);
1644 fi_root = NULL;
1645 fi_pos = NULL;
1646 rh = GNUNET_BIO_read_open_file (filename);
1647 if (NULL == rh)
1648 {
1649 GNUNET_break (0);
1650 goto cleanup;
1651 }
1652 struct GNUNET_BIO_ReadSpec rs[] = {
1653 GNUNET_BIO_read_spec_string ("publish-nid", &pc->nid, 1024),
1654 GNUNET_BIO_read_spec_string ("publish-nuid", &pc->nuid, 1024),
1655 GNUNET_BIO_read_spec_int32 ("options", &options),
1656 GNUNET_BIO_read_spec_int32 ("all done", &all_done),
1657 GNUNET_BIO_read_spec_int32 ("have ns", &have_ns),
1658 GNUNET_BIO_read_spec_string ("publish-firoot", &fi_root, 128),
1659 GNUNET_BIO_read_spec_string ("publish-fipos", &fi_pos, 128),
1660 GNUNET_BIO_read_spec_end (),
1661 };
1662 if ((GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) ||
1663 ((GNUNET_YES == have_ns) &&
1664 (GNUNET_OK != GNUNET_BIO_read (rh, "publish-ns", &ns, sizeof(ns)))))
1665 {
1666 GNUNET_break (0);
1667 goto cleanup;
1668 }
1669 pc->options = options;
1670 pc->all_done = all_done;
1671 if (NULL == fi_root)
1672 {
1673 GNUNET_break (0);
1674 goto cleanup;
1675 }
1676 pc->fi = deserialize_file_information (h, fi_root);
1677 if (NULL == pc->fi)
1678 {
1679 GNUNET_break (0);
1680 goto cleanup;
1681 }
1682 if (GNUNET_YES == have_ns)
1683 {
1684 pc->ns = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1685 *pc->ns = ns;
1686 }
1687 if ((0 == (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) &&
1688 (GNUNET_YES != pc->all_done))
1689 {
1690 pc->dsh = GNUNET_DATASTORE_connect (h->cfg);
1691 if (NULL == pc->dsh)
1692 goto cleanup;
1693 }
1694 if (NULL != fi_pos)
1695 {
1696 pc->fi_pos = find_file_position (pc->fi, fi_pos);
1697 GNUNET_free (fi_pos);
1698 fi_pos = NULL;
1699 if (NULL == pc->fi_pos)
1700 {
1701 /* failed to find position for resuming, outch! Will start from root! */
1702 GNUNET_break (0);
1703 if (GNUNET_YES != pc->all_done)
1704 pc->fi_pos = pc->fi;
1705 }
1706 }
1707 GNUNET_free (fi_root);
1708 fi_root = NULL;
1709 /* generate RESUME event(s) */
1710 GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_resume, pc);
1711
1712 /* re-start publishing (if needed)... */
1713 if (GNUNET_YES != pc->all_done)
1714 {
1715 GNUNET_assert (NULL == pc->upload_task);
1716 pc->upload_task =
1717 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
1718 &GNUNET_FS_publish_main_,
1719 pc);
1720 }
1721 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
1722 {
1723 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1724 _ ("Failure while resuming publishing operation `%s': %s\n"),
1725 filename,
1726 emsg);
1727 GNUNET_free (emsg);
1728 }
1729 pc->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, pc);
1730 return GNUNET_OK;
1731cleanup:
1732 GNUNET_free (pc->nid);
1733 GNUNET_free (pc->nuid);
1734 GNUNET_free (fi_root);
1735 GNUNET_free (fi_pos);
1736 if ((NULL != rh) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)))
1737 {
1738 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1739 _ ("Failed to resume publishing operation `%s': %s\n"),
1740 filename,
1741 emsg);
1742 GNUNET_free (emsg);
1743 }
1744 if (NULL != pc->fi)
1745 GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL);
1746 if (0 != unlink (filename))
1747 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
1748 GNUNET_free (pc->serialization);
1749 GNUNET_free (pc);
1750 return GNUNET_OK;
1751}
1752
1753
1754/**
1755 * Synchronize this publishing struct with its mirror
1756 * on disk. Note that all internal FS-operations that change
1757 * publishing structs should already call "sync" internally,
1758 * so this function is likely not useful for clients.
1759 *
1760 * @param pc the struct to sync
1761 */
1762void
1763GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc)
1764{
1765 struct GNUNET_BIO_WriteHandle *wh;
1766 int32_t have_ns;
1767
1768 if (NULL == pc->serialization)
1769 pc->serialization =
1770 make_serialization_file_name (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH);
1771 if (NULL == pc->serialization)
1772 return;
1773 if (NULL == pc->fi)
1774 return;
1775 if (NULL == pc->fi->serialization)
1776 {
1777 GNUNET_break (0);
1778 return;
1779 }
1780 wh = get_write_handle (pc->h,
1781 GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
1782 pc->serialization);
1783 if (NULL == wh)
1784 {
1785 GNUNET_break (0);
1786 goto cleanup;
1787 }
1788 have_ns = (NULL != pc->ns) ? GNUNET_YES : GNUNET_NO;
1789 struct GNUNET_BIO_WriteSpec ws[] = {
1790 GNUNET_BIO_write_spec_string ("nid", pc->nid),
1791 GNUNET_BIO_write_spec_string ("nuid", pc->nuid),
1792 GNUNET_BIO_write_spec_int32 ("options", (int32_t *) &pc->options),
1793 GNUNET_BIO_write_spec_int32 ("all done", &pc->all_done),
1794 GNUNET_BIO_write_spec_int32 ("have ns", &have_ns),
1795 GNUNET_BIO_write_spec_string ("serialization", pc->fi->serialization),
1796 GNUNET_BIO_write_spec_string ("pos serialization", (NULL == pc->fi_pos)
1797 ? NULL
1798 : pc->fi_pos->serialization),
1799 GNUNET_BIO_read_spec_end ()
1800 };
1801 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)) ||
1802 ((NULL != pc->ns) &&
1803 (GNUNET_OK !=
1804 GNUNET_BIO_write (wh,
1805 "ns",
1806 pc->ns,
1807 sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)))))
1808 {
1809 GNUNET_break (0);
1810 goto cleanup;
1811 }
1812 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
1813 {
1814 wh = NULL;
1815 GNUNET_break (0);
1816 goto cleanup;
1817 }
1818 return;
1819cleanup:
1820 if (NULL != wh)
1821 (void) GNUNET_BIO_write_close (wh, NULL);
1822 GNUNET_FS_remove_sync_file_ (pc->h,
1823 GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
1824 pc->serialization);
1825 GNUNET_free (pc->serialization);
1826 pc->serialization = NULL;
1827}
1828
1829
1830/**
1831 * Synchronize this unindex struct with its mirror
1832 * on disk. Note that all internal FS-operations that change
1833 * publishing structs should already call "sync" internally,
1834 * so this function is likely not useful for clients.
1835 *
1836 * @param uc the struct to sync
1837 */
1838void
1839GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc)
1840{
1841 struct GNUNET_BIO_WriteHandle *wh;
1842 char *uris;
1843
1844 if (NULL == uc->serialization)
1845 uc->serialization =
1846 make_serialization_file_name (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX);
1847 if (NULL == uc->serialization)
1848 return;
1849 wh = get_write_handle (uc->h,
1850 GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
1851 uc->serialization);
1852 if (NULL == wh)
1853 {
1854 GNUNET_break (0);
1855 goto cleanup;
1856 }
1857 if (NULL != uc->ksk_uri)
1858 uris = GNUNET_FS_uri_to_string (uc->ksk_uri);
1859 else
1860 uris = NULL;
1861 struct GNUNET_BIO_WriteSpec ws1[] = {
1862 GNUNET_BIO_write_spec_string ("filename", uc->filename),
1863 GNUNET_BIO_write_spec_int64 ("file size", (int64_t *) &uc->file_size),
1864 GNUNET_BIO_write_spec_end (),
1865 };
1866 struct GNUNET_BIO_WriteSpec ws2[] = {
1867 GNUNET_BIO_write_spec_int32 ("state", (int32_t *) &uc->state),
1868 GNUNET_BIO_write_spec_object ("hashkey", &uc->chk,
1869 sizeof (struct ContentHashKey)),
1870 GNUNET_BIO_write_spec_string ("uris", uris),
1871 GNUNET_BIO_write_spec_int32 ("ksk offset", (int32_t *) &uc->ksk_offset),
1872 GNUNET_BIO_write_spec_end (),
1873 };
1874 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws1)) ||
1875 (GNUNET_OK != write_start_time (wh, uc->start_time)) ||
1876 (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws2)) ||
1877 ((uc->state == UNINDEX_STATE_FS_NOTIFY) &&
1878 (GNUNET_OK != GNUNET_BIO_write (wh,
1879 "file id",
1880 &uc->file_id,
1881 sizeof(struct GNUNET_HashCode)))) ||
1882 ((uc->state == UNINDEX_STATE_ERROR) &&
1883 (GNUNET_OK != GNUNET_BIO_write_string (wh, "emsg", uc->emsg))))
1884 {
1885 GNUNET_break (0);
1886 goto cleanup;
1887 }
1888 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
1889 {
1890 wh = NULL;
1891 GNUNET_break (0);
1892 goto cleanup;
1893 }
1894 return;
1895cleanup:
1896 if (NULL != wh)
1897 (void) GNUNET_BIO_write_close (wh, NULL);
1898 GNUNET_FS_remove_sync_file_ (uc->h,
1899 GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
1900 uc->serialization);
1901 GNUNET_free (uc->serialization);
1902 uc->serialization = NULL;
1903}
1904
1905
1906/**
1907 * Serialize a download request.
1908 *
1909 * @param wh handle for writing the download request to disk
1910 * @param dr the the request to write to disk
1911 * @return #GNUNET_YES on success, #GNUNET_NO on error
1912 */
1913static int
1914write_download_request (struct GNUNET_BIO_WriteHandle *wh,
1915 struct DownloadRequest *dr)
1916{
1917 unsigned int i;
1918 struct GNUNET_BIO_WriteSpec ws[] = {
1919 GNUNET_BIO_write_spec_int32 ("state", (int32_t *) &dr->state),
1920 GNUNET_BIO_write_spec_int64 ("offset", (int64_t *) &dr->offset),
1921 GNUNET_BIO_write_spec_int32 ("num children", (int32_t *) &dr->num_children),
1922 GNUNET_BIO_write_spec_int32 ("depth", (int32_t *) &dr->depth),
1923 GNUNET_BIO_write_spec_end (),
1924 };
1925
1926 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)))
1927 return GNUNET_NO;
1928 if ((BRS_CHK_SET == dr->state) &&
1929 (GNUNET_OK !=
1930 GNUNET_BIO_write (wh, "hashkey",
1931 &dr->chk, sizeof(struct ContentHashKey))))
1932 return GNUNET_NO;
1933 for (i = 0; i < dr->num_children; i++)
1934 if (GNUNET_NO == write_download_request (wh, dr->children[i]))
1935 return GNUNET_NO;
1936 return GNUNET_YES;
1937}
1938
1939
1940/**
1941 * Read a download request tree.
1942 *
1943 * @param rh cadet to read from
1944 * @return value the download request read from disk, NULL on error
1945 */
1946static struct DownloadRequest *
1947read_download_request (struct GNUNET_BIO_ReadHandle *rh)
1948{
1949 struct DownloadRequest *dr;
1950 unsigned int i;
1951
1952 dr = GNUNET_new (struct DownloadRequest);
1953 struct GNUNET_BIO_ReadSpec rs[] = {
1954 GNUNET_BIO_read_spec_int32 ("state", (int32_t *) &dr->state),
1955 GNUNET_BIO_read_spec_int64 ("offset", (int64_t *) &dr->offset),
1956 GNUNET_BIO_read_spec_int32 ("num children", (int32_t *) &dr->num_children),
1957 GNUNET_BIO_read_spec_end (),
1958 };
1959 if ((GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) ||
1960 (dr->num_children > CHK_PER_INODE) ||
1961 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "depth",
1962 (int32_t *) &dr->depth)) ||
1963 ((0 == dr->depth) && (dr->num_children > 0)) ||
1964 ((dr->depth > 0) && (0 == dr->num_children)))
1965 {
1966 GNUNET_break (0);
1967 dr->num_children = 0;
1968 goto cleanup;
1969 }
1970 if (dr->num_children > 0)
1971 dr->children =
1972 GNUNET_malloc (dr->num_children * sizeof(struct DownloadRequest *));
1973 switch (dr->state)
1974 {
1975 case BRS_INIT:
1976 case BRS_RECONSTRUCT_DOWN:
1977 case BRS_RECONSTRUCT_META_UP:
1978 case BRS_RECONSTRUCT_UP:
1979 break;
1980
1981 case BRS_CHK_SET:
1982 if (GNUNET_OK !=
1983 GNUNET_BIO_read (rh, "chk", &dr->chk, sizeof(struct ContentHashKey)))
1984 goto cleanup;
1985 break;
1986
1987 case BRS_DOWNLOAD_DOWN:
1988 case BRS_DOWNLOAD_UP:
1989 case BRS_ERROR:
1990 break;
1991
1992 default:
1993 GNUNET_break (0);
1994 goto cleanup;
1995 }
1996 for (i = 0; i < dr->num_children; i++)
1997 {
1998 if (NULL == (dr->children[i] = read_download_request (rh)))
1999 goto cleanup;
2000 dr->children[i]->parent = dr;
2001 }
2002 return dr;
2003cleanup:
2004 GNUNET_FS_free_download_request_ (dr);
2005 return NULL;
2006}
2007
2008
2009/**
2010 * Compute the name of the sync file (or directory) for the given download
2011 * context.
2012 *
2013 * @param dc download context to compute for
2014 * @param uni unique filename to use, use "" for the directory name
2015 * @param ext extension to use, use ".dir" for our own subdirectory
2016 * @return the expanded file name, NULL for none
2017 */
2018static char *
2019get_download_sync_filename (struct GNUNET_FS_DownloadContext *dc,
2020 const char *uni,
2021 const char *ext)
2022{
2023 char *par;
2024 char *epar;
2025
2026 if (dc->parent == NULL)
2027 return get_serialization_file_name (dc->h,
2028 (dc->search != NULL)
2029 ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD
2030 : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
2031 uni);
2032 if (NULL == dc->parent->serialization)
2033 return NULL;
2034 par = get_download_sync_filename (dc->parent, dc->parent->serialization, "");
2035 if (NULL == par)
2036 return NULL;
2037 GNUNET_asprintf (&epar, "%s.dir%s%s%s", par, DIR_SEPARATOR_STR, uni, ext);
2038 GNUNET_free (par);
2039 return epar;
2040}
2041
2042
2043/**
2044 * Synchronize this download struct with its mirror
2045 * on disk. Note that all internal FS-operations that change
2046 * publishing structs should already call "sync" internally,
2047 * so this function is likely not useful for clients.
2048 *
2049 * @param dc the struct to sync
2050 */
2051void
2052GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc)
2053{
2054 struct GNUNET_BIO_WriteHandle *wh;
2055 char *uris;
2056 char *fn;
2057 char *dir;
2058
2059 if (0 != (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
2060 return; /* we don't sync probes */
2061 if (NULL == dc->serialization)
2062 {
2063 dir = get_download_sync_filename (dc, "", "");
2064 if (NULL == dir)
2065 return;
2066 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dir))
2067 {
2068 GNUNET_free (dir);
2069 return;
2070 }
2071 fn = GNUNET_DISK_mktemp (dir);
2072 GNUNET_free (dir);
2073 if (NULL == fn)
2074 return;
2075 dc->serialization = get_serialization_short_name (fn);
2076 }
2077 else
2078 {
2079 fn = get_download_sync_filename (dc, dc->serialization, "");
2080 if (NULL == fn)
2081 {
2082 GNUNET_free (dc->serialization);
2083 dc->serialization = NULL;
2084 GNUNET_free (fn);
2085 return;
2086 }
2087 }
2088 wh = GNUNET_BIO_write_open_file (fn);
2089 if (NULL == wh)
2090 {
2091 GNUNET_free (dc->serialization);
2092 dc->serialization = NULL;
2093 GNUNET_free (fn);
2094 return;
2095 }
2096 GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_chk (dc->uri)) ||
2097 (GNUNET_YES == GNUNET_FS_uri_test_loc (dc->uri)));
2098 uris = GNUNET_FS_uri_to_string (dc->uri);
2099 struct GNUNET_BIO_WriteSpec ws1[] = {
2100 GNUNET_BIO_write_spec_string ("uris", uris),
2101 GNUNET_BIO_write_spec_meta_data ("metadata", dc->meta),
2102 GNUNET_BIO_write_spec_string ("emsg", dc->emsg),
2103 GNUNET_BIO_write_spec_string ("filename", dc->filename),
2104 GNUNET_BIO_write_spec_string ("temp filename", dc->temp_filename),
2105 GNUNET_BIO_write_spec_int64 ("old file size",
2106 (int64_t *) &dc->old_file_size),
2107 GNUNET_BIO_write_spec_int64 ("offset", (int64_t *) &dc->offset),
2108 GNUNET_BIO_write_spec_int64 ("length", (int64_t *) &dc->length),
2109 GNUNET_BIO_write_spec_int64 ("completed", (int64_t *) &dc->completed),
2110 GNUNET_BIO_write_spec_end (),
2111 };
2112 struct GNUNET_BIO_WriteSpec ws2[] = {
2113 GNUNET_BIO_write_spec_int32 ("anonymity", (int32_t *) &dc->anonymity),
2114 GNUNET_BIO_write_spec_int32 ("options", (int32_t *) &dc->options),
2115 GNUNET_BIO_write_spec_int32 ("has finished", (int32_t *) &dc->has_finished),
2116 GNUNET_BIO_write_spec_end (),
2117 };
2118 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws1)) ||
2119 (GNUNET_OK != write_start_time (wh, dc->start_time)) ||
2120 (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws2)))
2121 {
2122 GNUNET_break (0);
2123 goto cleanup;
2124 }
2125 if (NULL == dc->emsg)
2126 {
2127 GNUNET_assert (dc->top_request != NULL);
2128 if (GNUNET_YES != write_download_request (wh, dc->top_request))
2129 {
2130 GNUNET_break (0);
2131 goto cleanup;
2132 }
2133 }
2134 GNUNET_free (uris);
2135 uris = NULL;
2136 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
2137 {
2138 wh = NULL;
2139 GNUNET_break (0);
2140 goto cleanup;
2141 }
2142 GNUNET_free (fn);
2143 return;
2144cleanup:
2145 if (NULL != wh)
2146 (void) GNUNET_BIO_write_close (wh, NULL);
2147 GNUNET_free (uris);
2148 if (0 != unlink (fn))
2149 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
2150 GNUNET_free (fn);
2151 GNUNET_free (dc->serialization);
2152 dc->serialization = NULL;
2153}
2154
2155
2156/**
2157 * Synchronize this search result with its mirror
2158 * on disk. Note that all internal FS-operations that change
2159 * publishing structs should already call "sync" internally,
2160 * so this function is likely not useful for clients.
2161 *
2162 * @param sr the struct to sync
2163 */
2164void
2165GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr)
2166{
2167 struct GNUNET_BIO_WriteHandle *wh;
2168 char *uris;
2169
2170 if (NULL == sr->sc)
2171 return;
2172 uris = NULL;
2173 if (NULL == sr->serialization)
2174 sr->serialization =
2175 make_serialization_file_name_in_dir (sr->h,
2176 (sr->sc->psearch_result == NULL)
2177 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2178 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
2179 sr->sc->serialization);
2180 if (NULL == sr->serialization)
2181 return;
2182 wh = get_write_handle_in_dir (sr->h,
2183 (sr->sc->psearch_result == NULL)
2184 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2185 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
2186 sr->sc->serialization,
2187 sr->serialization);
2188 if (NULL == wh)
2189 {
2190 GNUNET_break (0);
2191 goto cleanup;
2192 }
2193 uris = GNUNET_FS_uri_to_string (sr->uri);
2194 struct GNUNET_BIO_WriteSpec ws[] = {
2195 GNUNET_BIO_write_spec_string ("uris", uris),
2196 GNUNET_BIO_write_spec_string ("download serialization",
2197 (sr->download != NULL)
2198 ? sr->download->serialization
2199 : NULL),
2200 GNUNET_BIO_write_spec_string ("update search serialization",
2201 (sr->update_search != NULL)
2202 ? sr->update_search->serialization
2203 : NULL),
2204 GNUNET_BIO_write_spec_meta_data ("metadata", sr->meta),
2205 GNUNET_BIO_write_spec_object ("key", &sr->key,
2206 sizeof(struct GNUNET_HashCode)),
2207 GNUNET_BIO_write_spec_int32 ("mandatory missing",
2208 (int32_t *) &sr->mandatory_missing),
2209 GNUNET_BIO_write_spec_int32 ("optional support",
2210 (int32_t *) &sr->optional_support),
2211 GNUNET_BIO_write_spec_int32 ("availability success",
2212 (int32_t *) &sr->availability_success),
2213 GNUNET_BIO_write_spec_int32 ("availability trials",
2214 (int32_t *) &sr->availability_trials),
2215 GNUNET_BIO_write_spec_end (),
2216 };
2217 if ((GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws)))
2218 {
2219 GNUNET_break (0);
2220 goto cleanup;
2221 }
2222 if ((NULL != sr->uri) && (GNUNET_FS_URI_KSK == sr->sc->uri->type) &&
2223 (GNUNET_OK !=
2224 GNUNET_BIO_write (wh,
2225 "keyword bitmap",
2226 sr->keyword_bitmap,
2227 (sr->sc->uri->data.ksk.keywordCount + 7) / 8)))
2228 {
2229 GNUNET_break (0);
2230 goto cleanup;
2231 }
2232 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
2233 {
2234 wh = NULL;
2235 GNUNET_break (0);
2236 goto cleanup;
2237 }
2238 GNUNET_free (uris);
2239 return;
2240cleanup:
2241 GNUNET_free (uris);
2242 if (NULL != wh)
2243 (void) GNUNET_BIO_write_close (wh, NULL);
2244 remove_sync_file_in_dir (sr->h,
2245 (NULL == sr->sc->psearch_result)
2246 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2247 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
2248 sr->sc->serialization,
2249 sr->serialization);
2250 GNUNET_free (sr->serialization);
2251 sr->serialization = NULL;
2252}
2253
2254
2255/**
2256 * Synchronize this search struct with its mirror
2257 * on disk. Note that all internal FS-operations that change
2258 * publishing structs should already call "sync" internally,
2259 * so this function is likely not useful for clients.
2260 *
2261 * @param sc the struct to sync
2262 */
2263void
2264GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc)
2265{
2266 struct GNUNET_BIO_WriteHandle *wh;
2267 char *uris;
2268 char in_pause;
2269 const char *category;
2270
2271 category = (NULL == sc->psearch_result) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2272 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH;
2273 if (NULL == sc->serialization)
2274 sc->serialization = make_serialization_file_name (sc->h, category);
2275 if (NULL == sc->serialization)
2276 return;
2277 uris = NULL;
2278 wh = get_write_handle (sc->h, category, sc->serialization);
2279 if (NULL == wh)
2280 {
2281 GNUNET_break (0);
2282 goto cleanup;
2283 }
2284 GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_ksk (sc->uri)) ||
2285 (GNUNET_YES == GNUNET_FS_uri_test_sks (sc->uri)));
2286 uris = GNUNET_FS_uri_to_string (sc->uri);
2287 in_pause = (sc->task != NULL) ? 'r' : '\0';
2288 if ((GNUNET_OK != GNUNET_BIO_write_string (wh, "uris", uris)) ||
2289 (GNUNET_OK != write_start_time (wh, sc->start_time)) ||
2290 (GNUNET_OK != GNUNET_BIO_write_string (wh, "emsg", sc->emsg)) ||
2291 (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "options",
2292 (uint32_t) sc->options)) ||
2293 (GNUNET_OK != GNUNET_BIO_write (wh, "in pause",
2294 &in_pause, sizeof(in_pause))) ||
2295 (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "anonymity", sc->anonymity)))
2296 {
2297 GNUNET_break (0);
2298 goto cleanup;
2299 }
2300 GNUNET_free (uris);
2301 uris = NULL;
2302 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
2303 {
2304 wh = NULL;
2305 GNUNET_break (0);
2306 goto cleanup;
2307 }
2308 return;
2309cleanup:
2310 if (NULL != wh)
2311 (void) GNUNET_BIO_write_close (wh, NULL);
2312 GNUNET_free (uris);
2313 GNUNET_FS_remove_sync_file_ (sc->h, category, sc->serialization);
2314 GNUNET_free (sc->serialization);
2315 sc->serialization = NULL;
2316}
2317
2318
2319/**
2320 * Function called with a filename of serialized unindexing operation
2321 * to deserialize.
2322 *
2323 * @param cls the `struct GNUNET_FS_Handle *`
2324 * @param filename complete filename (absolute path)
2325 * @return #GNUNET_OK (continue to iterate)
2326 */
2327static int
2328deserialize_unindex_file (void *cls, const char *filename)
2329{
2330 struct GNUNET_FS_Handle *h = cls;
2331 struct GNUNET_BIO_ReadHandle *rh;
2332 struct GNUNET_FS_UnindexContext *uc;
2333 struct GNUNET_FS_ProgressInfo pi;
2334 char *emsg;
2335 char *uris;
2336 uint32_t state;
2337
2338 uc = GNUNET_new (struct GNUNET_FS_UnindexContext);
2339 uc->h = h;
2340 uc->serialization = get_serialization_short_name (filename);
2341 rh = GNUNET_BIO_read_open_file (filename);
2342 if (NULL == rh)
2343 {
2344 GNUNET_break (0);
2345 goto cleanup;
2346 }
2347 uris = NULL;
2348 if ((GNUNET_OK !=
2349 GNUNET_BIO_read_string (rh, "unindex-fn", &uc->filename, 10 * 1024)) ||
2350 (GNUNET_OK != GNUNET_BIO_read_int64 (rh, "file size",
2351 (int64_t *) &uc->file_size)) ||
2352 (GNUNET_OK != read_start_time (rh, &uc->start_time)) ||
2353 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "state",
2354 (int32_t *) &state)) ||
2355 (GNUNET_OK !=
2356 GNUNET_BIO_read (rh, "uri", &uc->chk, sizeof(struct ContentHashKey))) ||
2357 (GNUNET_OK !=
2358 GNUNET_BIO_read_string (rh, "unindex-kskuri", &uris, 10 * 1024)) ||
2359 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "ksk offset",
2360 (int32_t *) &uc->ksk_offset)))
2361 {
2362 GNUNET_free (uris);
2363 GNUNET_break (0);
2364 goto cleanup;
2365 }
2366 if (NULL != uris)
2367 {
2368 uc->ksk_uri = GNUNET_FS_uri_parse (uris, &emsg);
2369 GNUNET_free (uris);
2370 if (NULL == uc->ksk_uri)
2371 {
2372 GNUNET_break (0);
2373 GNUNET_free (emsg);
2374 goto cleanup;
2375 }
2376 }
2377 if ((uc->ksk_offset > 0) &&
2378 ((NULL == uc->ksk_uri) ||
2379 (uc->ksk_offset > uc->ksk_uri->data.ksk.keywordCount)))
2380 {
2381 GNUNET_break (0);
2382 goto cleanup;
2383 }
2384 uc->state = (enum UnindexState) state;
2385 switch (state)
2386 {
2387 case UNINDEX_STATE_HASHING:
2388 break;
2389
2390 case UNINDEX_STATE_FS_NOTIFY:
2391 if (GNUNET_OK != GNUNET_BIO_read (rh,
2392 "unindex-hash",
2393 &uc->file_id,
2394 sizeof(struct GNUNET_HashCode)))
2395 {
2396 GNUNET_break (0);
2397 goto cleanup;
2398 }
2399 break;
2400
2401 case UNINDEX_STATE_DS_REMOVE:
2402 case UNINDEX_STATE_EXTRACT_KEYWORDS:
2403 case UNINDEX_STATE_DS_REMOVE_KBLOCKS:
2404 break;
2405
2406 case UNINDEX_STATE_COMPLETE:
2407 break;
2408
2409 case UNINDEX_STATE_ERROR:
2410 if (GNUNET_OK !=
2411 GNUNET_BIO_read_string (rh, "unindex-emsg", &uc->emsg, 10 * 1024))
2412 {
2413 GNUNET_break (0);
2414 goto cleanup;
2415 }
2416 break;
2417
2418 default:
2419 GNUNET_break (0);
2420 goto cleanup;
2421 }
2422 uc->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, uc);
2423 pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME;
2424 pi.value.unindex.specifics.resume.message = uc->emsg;
2425 GNUNET_FS_unindex_make_status_ (&pi,
2426 uc,
2427 (uc->state == UNINDEX_STATE_COMPLETE)
2428 ? uc->file_size
2429 : 0);
2430 switch (uc->state)
2431 {
2432 case UNINDEX_STATE_HASHING:
2433 uc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
2434 uc->filename,
2435 HASHING_BLOCKSIZE,
2436 &GNUNET_FS_unindex_process_hash_,
2437 uc);
2438 break;
2439
2440 case UNINDEX_STATE_FS_NOTIFY:
2441 uc->state = UNINDEX_STATE_HASHING;
2442 GNUNET_FS_unindex_process_hash_ (uc, &uc->file_id);
2443 break;
2444
2445 case UNINDEX_STATE_DS_REMOVE:
2446 GNUNET_FS_unindex_do_remove_ (uc);
2447 break;
2448
2449 case UNINDEX_STATE_EXTRACT_KEYWORDS:
2450 GNUNET_FS_unindex_do_extract_keywords_ (uc);
2451 break;
2452
2453 case UNINDEX_STATE_DS_REMOVE_KBLOCKS:
2454 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
2455 break;
2456
2457 case UNINDEX_STATE_COMPLETE:
2458 case UNINDEX_STATE_ERROR:
2459 /* no need to resume any operation, we were done */
2460 break;
2461
2462 default:
2463 break;
2464 }
2465 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
2466 {
2467 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2468 _ ("Failure while resuming unindexing operation `%s': %s\n"),
2469 filename,
2470 emsg);
2471 GNUNET_free (emsg);
2472 }
2473 return GNUNET_OK;
2474cleanup:
2475 GNUNET_free (uc->filename);
2476 if ((NULL != rh) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)))
2477 {
2478 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2479 _ ("Failed to resume unindexing operation `%s': %s\n"),
2480 filename,
2481 emsg);
2482 GNUNET_free (emsg);
2483 }
2484 if (NULL != uc->serialization)
2485 GNUNET_FS_remove_sync_file_ (h,
2486 GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
2487 uc->serialization);
2488 GNUNET_free (uc->serialization);
2489 GNUNET_free (uc);
2490 return GNUNET_OK;
2491}
2492
2493
2494/**
2495 * Deserialize a download.
2496 *
2497 * @param h overall context
2498 * @param rh file to deserialize from
2499 * @param parent parent download
2500 * @param search associated search
2501 * @param serialization name under which the search was serialized
2502 */
2503static void
2504deserialize_download (struct GNUNET_FS_Handle *h,
2505 struct GNUNET_BIO_ReadHandle *rh,
2506 struct GNUNET_FS_DownloadContext *parent,
2507 struct GNUNET_FS_SearchResult *search,
2508 const char *serialization);
2509
2510
2511/**
2512 * Deserialize a search.
2513 *
2514 * @param h overall context
2515 * @param rh file to deserialize from
2516 * @param psearch_result parent search result
2517 * @param serialization name under which the search was serialized
2518 */
2519static struct GNUNET_FS_SearchContext *
2520deserialize_search (struct GNUNET_FS_Handle *h,
2521 struct GNUNET_BIO_ReadHandle *rh,
2522 struct GNUNET_FS_SearchResult *psearch_result,
2523 const char *serialization);
2524
2525
2526/**
2527 * Function called with a filename of serialized search result
2528 * to deserialize.
2529 *
2530 * @param cls the `struct GNUNET_FS_SearchContext *`
2531 * @param filename complete filename (absolute path)
2532 * @return #GNUNET_OK (continue to iterate)
2533 */
2534static int
2535deserialize_search_result (void *cls, const char *filename)
2536{
2537 struct GNUNET_FS_SearchContext *sc = cls;
2538 char *serialized;
2539 char *uris;
2540 char *emsg;
2541 char *download;
2542 char *update_srch;
2543 struct GNUNET_BIO_ReadHandle *rh;
2544 struct GNUNET_BIO_ReadHandle *drh;
2545 struct GNUNET_FS_SearchResult *sr;
2546
2547 serialized = get_serialization_short_name (filename);
2548 rh = GNUNET_BIO_read_open_file (filename);
2549 if (NULL == rh)
2550 {
2551 if (NULL != serialized)
2552 {
2553 remove_sync_file_in_dir (sc->h,
2554 (NULL == sc->psearch_result)
2555 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2556 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
2557 sc->serialization,
2558 serialized);
2559 GNUNET_free (serialized);
2560 }
2561 return GNUNET_OK;
2562 }
2563 emsg = NULL;
2564 uris = NULL;
2565 download = NULL;
2566 update_srch = NULL;
2567 sr = GNUNET_new (struct GNUNET_FS_SearchResult);
2568 sr->h = sc->h;
2569 sr->sc = sc;
2570 sr->serialization = serialized;
2571 if ((GNUNET_OK !=
2572 GNUNET_BIO_read_string (rh, "result-uri", &uris, 10 * 1024)) ||
2573 (NULL == (sr->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
2574 (GNUNET_OK !=
2575 GNUNET_BIO_read_string (rh, "download-lnk", &download, 16)) ||
2576 (GNUNET_OK !=
2577 GNUNET_BIO_read_string (rh, "search-lnk", &update_srch, 16)) ||
2578 (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "result-meta", &sr->meta)) ||
2579 (GNUNET_OK != GNUNET_BIO_read (rh,
2580 "result-key",
2581 &sr->key,
2582 sizeof(struct GNUNET_HashCode))) ||
2583 (GNUNET_OK != GNUNET_BIO_read_int32 (
2584 rh,
2585 "mandatory missing",
2586 (int32_t *) &sr->mandatory_missing)) ||
2587 (GNUNET_OK != GNUNET_BIO_read_int32 (
2588 rh,
2589 "optional support",
2590 (int32_t *) &sr->optional_support)) ||
2591 (GNUNET_OK != GNUNET_BIO_read_int32 (
2592 rh,
2593 "availability success",
2594 (int32_t *) &sr->availability_success)) ||
2595 (GNUNET_OK != GNUNET_BIO_read_int32 (
2596 rh,
2597 "availability trials",
2598 (int32_t *) &sr->availability_trials)))
2599 {
2600 GNUNET_break (0);
2601 goto cleanup;
2602 }
2603 if (GNUNET_FS_URI_KSK == sr->sc->uri->type)
2604 {
2605 sr->keyword_bitmap = GNUNET_malloc (
2606 (sr->sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */
2607 if (GNUNET_OK !=
2608 GNUNET_BIO_read (rh,
2609 "keyword-bitmap",
2610 sr->keyword_bitmap,
2611 (sr->sc->uri->data.ksk.keywordCount + 7) / 8))
2612 {
2613 GNUNET_break (0);
2614 goto cleanup;
2615 }
2616 }
2617 GNUNET_free (uris);
2618 if (NULL != download)
2619 {
2620 drh = get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, download);
2621 if (NULL != drh)
2622 {
2623 deserialize_download (sc->h, drh, NULL, sr, download);
2624 if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg))
2625 {
2626 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2627 _ ("Failed to resume sub-download `%s': %s\n"),
2628 download,
2629 emsg);
2630 GNUNET_free (emsg);
2631 }
2632 }
2633 GNUNET_free (download);
2634 }
2635 if (NULL != update_srch)
2636 {
2637 drh =
2638 get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_SEARCH, update_srch);
2639 if (NULL != drh)
2640 {
2641 deserialize_search (sc->h, drh, sr, update_srch);
2642 if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg))
2643 {
2644 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2645 _ ("Failed to resume sub-search `%s': %s\n"),
2646 update_srch,
2647 emsg);
2648 GNUNET_free (emsg);
2649 }
2650 }
2651 GNUNET_free (update_srch);
2652 }
2653 GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (
2654 sc->master_result_map,
2655 &sr->key,
2656 sr,
2657 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2658 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
2659 {
2660 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2661 _ ("Failure while resuming search operation `%s': %s\n"),
2662 filename,
2663 emsg);
2664 GNUNET_free (emsg);
2665 }
2666 return GNUNET_OK;
2667cleanup:
2668 GNUNET_free (download);
2669 GNUNET_free (emsg);
2670 GNUNET_free (uris);
2671 GNUNET_free (update_srch);
2672 if (NULL != sr->uri)
2673 GNUNET_FS_uri_destroy (sr->uri);
2674 if (NULL != sr->meta)
2675 GNUNET_CONTAINER_meta_data_destroy (sr->meta);
2676 GNUNET_free (sr->serialization);
2677 GNUNET_free (sr);
2678 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
2679 {
2680 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2681 _ ("Failure while resuming search operation `%s': %s\n"),
2682 filename,
2683 emsg);
2684 GNUNET_free (emsg);
2685 }
2686 return GNUNET_OK;
2687}
2688
2689
2690/**
2691 * Send the 'resume' signal to the callback; also actually
2692 * resume the download (put it in the queue). Does this
2693 * recursively for the top-level download and all child
2694 * downloads.
2695 *
2696 * @param dc download to resume
2697 */
2698static void
2699signal_download_resume (struct GNUNET_FS_DownloadContext *dc)
2700{
2701 struct GNUNET_FS_DownloadContext *dcc;
2702 struct GNUNET_FS_ProgressInfo pi;
2703
2704 pi.status = GNUNET_FS_STATUS_DOWNLOAD_RESUME;
2705 pi.value.download.specifics.resume.meta = dc->meta;
2706 pi.value.download.specifics.resume.message = dc->emsg;
2707 GNUNET_FS_download_make_status_ (&pi, dc);
2708 dcc = dc->child_head;
2709 while (NULL != dcc)
2710 {
2711 signal_download_resume (dcc);
2712 dcc = dcc->next;
2713 }
2714}
2715
2716
2717/**
2718 * Signal resuming of a search to our clients (for the
2719 * top level search and all sub-searches).
2720 *
2721 * @param sc search being resumed
2722 */
2723static void
2724signal_search_resume (struct GNUNET_FS_SearchContext *sc);
2725
2726
2727/**
2728 * Iterator over search results signaling resume to the client for
2729 * each result.
2730 *
2731 * @param cls closure, the `struct GNUNET_FS_SearchContext *`
2732 * @param key current key code
2733 * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *`
2734 * @return #GNUNET_YES (we should continue to iterate)
2735 */
2736static int
2737signal_result_resume (void *cls, const struct GNUNET_HashCode *key, void *value)
2738{
2739 struct GNUNET_FS_SearchContext *sc = cls;
2740 struct GNUNET_FS_ProgressInfo pi;
2741 struct GNUNET_FS_SearchResult *sr = value;
2742
2743 if (0 == sr->mandatory_missing)
2744 {
2745 pi.status = GNUNET_FS_STATUS_SEARCH_RESUME_RESULT;
2746 pi.value.search.specifics.resume_result.meta = sr->meta;
2747 pi.value.search.specifics.resume_result.uri = sr->uri;
2748 pi.value.search.specifics.resume_result.result = sr;
2749 pi.value.search.specifics.resume_result.availability_rank =
2750 2 * sr->availability_success - sr->availability_trials;
2751 pi.value.search.specifics.resume_result.availability_certainty =
2752 sr->availability_trials;
2753 pi.value.search.specifics.resume_result.applicability_rank =
2754 sr->optional_support;
2755 sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
2756 }
2757 if (NULL != sr->download)
2758 {
2759 signal_download_resume (sr->download);
2760 }
2761 else
2762 {
2763 GNUNET_FS_search_start_probe_ (sr);
2764 }
2765 if (NULL != sr->update_search)
2766 signal_search_resume (sr->update_search);
2767 return GNUNET_YES;
2768}
2769
2770
2771/**
2772 * Free memory allocated by the search context and its children
2773 *
2774 * @param sc search context to free
2775 */
2776static void
2777free_search_context (struct GNUNET_FS_SearchContext *sc);
2778
2779
2780/**
2781 * Iterator over search results freeing each.
2782 *
2783 * @param cls closure, the `struct GNUNET_FS_SearchContext *`
2784 * @param key current key code
2785 * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *`
2786 * @return #GNUNET_YES (we should continue to iterate)
2787 */
2788static int
2789free_result (void *cls, const struct GNUNET_HashCode *key, void *value)
2790{
2791 struct GNUNET_FS_SearchResult *sr = value;
2792
2793 if (NULL != sr->update_search)
2794 {
2795 free_search_context (sr->update_search);
2796 GNUNET_assert (NULL == sr->update_search);
2797 }
2798 GNUNET_CONTAINER_meta_data_destroy (sr->meta);
2799 GNUNET_FS_uri_destroy (sr->uri);
2800 GNUNET_free (sr);
2801 return GNUNET_YES;
2802}
2803
2804
2805/**
2806 * Free memory allocated by the search context and its children
2807 *
2808 * @param sc search context to free
2809 */
2810static void
2811free_search_context (struct GNUNET_FS_SearchContext *sc)
2812{
2813 if (NULL != sc->serialization)
2814 {
2815 GNUNET_FS_remove_sync_file_ (sc->h,
2816 (sc->psearch_result == NULL)
2817 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2818 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
2819 sc->serialization);
2820 GNUNET_FS_remove_sync_dir_ (sc->h,
2821 (sc->psearch_result == NULL)
2822 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
2823 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
2824 sc->serialization);
2825 }
2826 GNUNET_free (sc->serialization);
2827 GNUNET_free (sc->emsg);
2828 if (NULL != sc->uri)
2829 GNUNET_FS_uri_destroy (sc->uri);
2830 if (NULL != sc->master_result_map)
2831 {
2832 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
2833 &free_result,
2834 sc);
2835 GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
2836 }
2837 GNUNET_free (sc);
2838}
2839
2840
2841/**
2842 * Function called with a filename of serialized sub-download
2843 * to deserialize.
2844 *
2845 * @param cls the `struct GNUNET_FS_DownloadContext *` (parent)
2846 * @param filename complete filename (absolute path)
2847 * @return #GNUNET_OK (continue to iterate)
2848 */
2849static int
2850deserialize_subdownload (void *cls, const char *filename)
2851{
2852 struct GNUNET_FS_DownloadContext *parent = cls;
2853 char *serialized;
2854 char *emsg;
2855 struct GNUNET_BIO_ReadHandle *rh;
2856
2857 serialized = get_serialization_short_name (filename);
2858 rh = GNUNET_BIO_read_open_file (filename);
2859 if (NULL == rh)
2860 {
2861 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2862 _ (
2863 "Failed to resume sub-download `%s': could not open file `%s'\n"),
2864 serialized,
2865 filename);
2866 GNUNET_free (serialized);
2867 return GNUNET_OK;
2868 }
2869 deserialize_download (parent->h, rh, parent, NULL, serialized);
2870 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
2871 {
2872 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2873 _ ("Failed to resume sub-download `%s': %s\n"),
2874 serialized,
2875 emsg);
2876 GNUNET_free (emsg);
2877 }
2878 GNUNET_free (serialized);
2879 return GNUNET_OK;
2880}
2881
2882
2883/**
2884 * Free this download context and all of its descendants.
2885 * (only works during deserialization since not all possible
2886 * state it taken care of).
2887 *
2888 * @param dc context to free
2889 */
2890static void
2891free_download_context (struct GNUNET_FS_DownloadContext *dc)
2892{
2893 struct GNUNET_FS_DownloadContext *dcc;
2894
2895 if (NULL != dc->meta)
2896 GNUNET_CONTAINER_meta_data_destroy (dc->meta);
2897 if (NULL != dc->uri)
2898 GNUNET_FS_uri_destroy (dc->uri);
2899 GNUNET_free (dc->temp_filename);
2900 GNUNET_free (dc->emsg);
2901 GNUNET_free (dc->filename);
2902 GNUNET_free (dc->serialization);
2903 while (NULL != (dcc = dc->child_head))
2904 {
2905 GNUNET_CONTAINER_DLL_remove (dc->child_head, dc->child_tail, dcc);
2906 free_download_context (dcc);
2907 }
2908 GNUNET_FS_free_download_request_ (dc->top_request);
2909 if (NULL != dc->active)
2910 GNUNET_CONTAINER_multihashmap_destroy (dc->active);
2911 GNUNET_free (dc);
2912}
2913
2914
2915/**
2916 * Deserialize a download.
2917 *
2918 * @param h overall context
2919 * @param rh file to deserialize from
2920 * @param parent parent download
2921 * @param search associated search
2922 * @param serialization name under which the search was serialized
2923 */
2924static void
2925deserialize_download (struct GNUNET_FS_Handle *h,
2926 struct GNUNET_BIO_ReadHandle *rh,
2927 struct GNUNET_FS_DownloadContext *parent,
2928 struct GNUNET_FS_SearchResult *search,
2929 const char *serialization)
2930{
2931 struct GNUNET_FS_DownloadContext *dc;
2932 char *emsg;
2933 char *uris;
2934 char *dn;
2935 uint32_t options;
2936 uint32_t status;
2937
2938 uris = NULL;
2939 emsg = NULL;
2940 dc = GNUNET_new (struct GNUNET_FS_DownloadContext);
2941 dc->parent = parent;
2942 dc->h = h;
2943 dc->serialization = GNUNET_strdup (serialization);
2944 struct GNUNET_BIO_ReadSpec rs[] = {
2945 GNUNET_BIO_read_spec_meta_data ("download-meta", &dc->meta),
2946 GNUNET_BIO_read_spec_string ("download-emsg", &dc->emsg, 10 * 1024),
2947 GNUNET_BIO_read_spec_string ("download-fn", &dc->filename, 10 * 1024),
2948 GNUNET_BIO_read_spec_string ("download-tfn",
2949 &dc->temp_filename, 10 * 1024),
2950 GNUNET_BIO_read_spec_int64 ("old file size",
2951 (int64_t *) &dc->old_file_size),
2952 GNUNET_BIO_read_spec_int64 ("offset",
2953 (int64_t *) &dc->offset),
2954 GNUNET_BIO_read_spec_int64 ("length",
2955 (int64_t *) &dc->length),
2956 GNUNET_BIO_read_spec_int64 ("completed",
2957 (int64_t *) &dc->completed),
2958 GNUNET_BIO_read_spec_end (),
2959 };
2960 if ((GNUNET_OK !=
2961 GNUNET_BIO_read_string (rh, "download-uri", &uris, 10 * 1024)) ||
2962 (NULL == (dc->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
2963 ((GNUNET_YES != GNUNET_FS_uri_test_chk (dc->uri)) &&
2964 (GNUNET_YES != GNUNET_FS_uri_test_loc (dc->uri))) ||
2965 (GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs)) ||
2966 (GNUNET_OK != read_start_time (rh, &dc->start_time)) ||
2967 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "anonymity",
2968 (int32_t *) &dc->anonymity)) ||
2969 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "options",
2970 (int32_t *) &options)) ||
2971 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "status",
2972 (int32_t *) &status)))
2973 {
2974 GNUNET_break (0);
2975 goto cleanup;
2976 }
2977 dc->options = (enum GNUNET_FS_DownloadOptions) options;
2978 dc->active =
2979 GNUNET_CONTAINER_multihashmap_create (1 + 2 * (dc->length / DBLOCK_SIZE),
2980 GNUNET_NO);
2981 dc->has_finished = (int) status;
2982 dc->treedepth =
2983 GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri));
2984 if (GNUNET_FS_uri_test_loc (dc->uri))
2985 GNUNET_assert (GNUNET_OK ==
2986 GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target));
2987 if (NULL == dc->emsg)
2988 {
2989 dc->top_request = read_download_request (rh);
2990 if (NULL == dc->top_request)
2991 {
2992 GNUNET_break (0);
2993 goto cleanup;
2994 }
2995 }
2996 dn = get_download_sync_filename (dc, dc->serialization, ".dir");
2997 if (NULL != dn)
2998 {
2999 if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES))
3000 GNUNET_DISK_directory_scan (dn, &deserialize_subdownload, dc);
3001 GNUNET_free (dn);
3002 }
3003 if (NULL != parent)
3004 {
3005 GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc);
3006 }
3007 if (NULL != search)
3008 {
3009 dc->search = search;
3010 search->download = dc;
3011 }
3012 if ((NULL == parent) && (NULL == search))
3013 {
3014 dc->top =
3015 GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc);
3016 signal_download_resume (dc);
3017 }
3018 GNUNET_free (uris);
3019 GNUNET_assert (NULL == dc->job_queue);
3020 dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc);
3021 return;
3022cleanup:
3023 GNUNET_free (uris);
3024 GNUNET_free (emsg);
3025 free_download_context (dc);
3026}
3027
3028
3029/**
3030 * Signal resuming of a search to our clients (for the
3031 * top level search and all sub-searches).
3032 *
3033 * @param sc search being resumed
3034 */
3035static void
3036signal_search_resume (struct GNUNET_FS_SearchContext *sc)
3037{
3038 struct GNUNET_FS_ProgressInfo pi;
3039
3040 pi.status = GNUNET_FS_STATUS_SEARCH_RESUME;
3041 pi.value.search.specifics.resume.message = sc->emsg;
3042 pi.value.search.specifics.resume.is_paused =
3043 (NULL == sc->mq) ? GNUNET_YES : GNUNET_NO;
3044 sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
3045 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
3046 &signal_result_resume,
3047 sc);
3048}
3049
3050
3051/**
3052 * Deserialize a search.
3053 *
3054 * @param h overall context
3055 * @param rh file to deserialize from
3056 * @param psearch_result parent search result
3057 * @param serialization name under which the search was serialized
3058 */
3059static struct GNUNET_FS_SearchContext *
3060deserialize_search (struct GNUNET_FS_Handle *h,
3061 struct GNUNET_BIO_ReadHandle *rh,
3062 struct GNUNET_FS_SearchResult *psearch_result,
3063 const char *serialization)
3064{
3065 struct GNUNET_FS_SearchContext *sc;
3066 char *emsg;
3067 char *uris;
3068 char *dn;
3069 uint32_t options;
3070 char in_pause;
3071
3072 if ((NULL != psearch_result) && (NULL != psearch_result->update_search))
3073 {
3074 GNUNET_break (0);
3075 return NULL;
3076 }
3077 uris = NULL;
3078 emsg = NULL;
3079 sc = GNUNET_new (struct GNUNET_FS_SearchContext);
3080 if (NULL != psearch_result)
3081 {
3082 sc->psearch_result = psearch_result;
3083 psearch_result->update_search = sc;
3084 }
3085 sc->h = h;
3086 sc->serialization = GNUNET_strdup (serialization);
3087 if ((GNUNET_OK !=
3088 GNUNET_BIO_read_string (rh, "search-uri", &uris, 10 * 1024)) ||
3089 (NULL == (sc->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
3090 ((GNUNET_YES != GNUNET_FS_uri_test_ksk (sc->uri)) &&
3091 (GNUNET_YES != GNUNET_FS_uri_test_sks (sc->uri))) ||
3092 (GNUNET_OK != read_start_time (rh, &sc->start_time)) ||
3093 (GNUNET_OK !=
3094 GNUNET_BIO_read_string (rh, "search-emsg", &sc->emsg, 10 * 1024)) ||
3095 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "options",
3096 (int32_t *) &options)) ||
3097 (GNUNET_OK !=
3098 GNUNET_BIO_read (rh, "search-pause", &in_pause, sizeof(in_pause))) ||
3099 (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "anonymity",
3100 (int32_t *) &sc->anonymity)))
3101 {
3102 GNUNET_break (0);
3103 goto cleanup;
3104 }
3105 sc->options = (enum GNUNET_FS_SearchOptions) options;
3106 sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
3107 dn = get_serialization_file_name_in_dir (h,
3108 (NULL == sc->psearch_result)
3109 ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
3110 : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
3111 sc->serialization,
3112 "");
3113 if (NULL != dn)
3114 {
3115 if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES))
3116 GNUNET_DISK_directory_scan (dn, &deserialize_search_result, sc);
3117 GNUNET_free (dn);
3118 }
3119 if (('\0' == in_pause) &&
3120 (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc)))
3121 {
3122 GNUNET_log (
3123 GNUNET_ERROR_TYPE_WARNING,
3124 _ ("Could not resume running search, will resume as paused search\n"));
3125 }
3126 signal_search_resume (sc);
3127 GNUNET_free (uris);
3128 return sc;
3129cleanup:
3130 GNUNET_free (emsg);
3131 free_search_context (sc);
3132 GNUNET_free (uris);
3133 return NULL;
3134}
3135
3136
3137/**
3138 * Function called with a filename of serialized search operation
3139 * to deserialize.
3140 *
3141 * @param cls the `struct GNUNET_FS_Handle *`
3142 * @param filename complete filename (absolute path)
3143 * @return #GNUNET_OK (continue to iterate)
3144 */
3145static int
3146deserialize_search_file (void *cls, const char *filename)
3147{
3148 struct GNUNET_FS_Handle *h = cls;
3149 char *set;
3150 char *emsg;
3151 struct GNUNET_BIO_ReadHandle *rh;
3152 struct GNUNET_FS_SearchContext *sc;
3153 struct stat buf;
3154
3155 if (0 != stat (filename, &buf))
3156 {
3157 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
3158 return GNUNET_OK;
3159 }
3160 if (S_ISDIR (buf.st_mode))
3161 return GNUNET_OK; /* skip directories */
3162 set = get_serialization_short_name (filename);
3163 rh = GNUNET_BIO_read_open_file (filename);
3164 if (NULL == rh)
3165 {
3166 if (NULL != set)
3167 {
3168 GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_SEARCH, set);
3169 GNUNET_free (set);
3170 }
3171 return GNUNET_OK;
3172 }
3173 sc = deserialize_search (h, rh, NULL, set);
3174 if (NULL != sc)
3175 sc->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, sc);
3176 GNUNET_free (set);
3177 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
3178 {
3179 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3180 _ ("Failure while resuming search operation `%s': %s\n"),
3181 filename,
3182 emsg);
3183 GNUNET_free (emsg);
3184 }
3185 return GNUNET_OK;
3186}
3187
3188
3189/**
3190 * Function called with a filename of serialized download operation
3191 * to deserialize.
3192 *
3193 * @param cls the `struct GNUNET_FS_Handle *`
3194 * @param filename complete filename (absolute path)
3195 * @return #GNUNET_OK (continue to iterate)
3196 */
3197static int
3198deserialize_download_file (void *cls, const char *filename)
3199{
3200 struct GNUNET_FS_Handle *h = cls;
3201 char *set;
3202 char *emsg;
3203 struct GNUNET_BIO_ReadHandle *rh;
3204
3205 set = get_serialization_short_name (filename);
3206 rh = GNUNET_BIO_read_open_file (filename);
3207 if (NULL == rh)
3208 {
3209 if (0 != unlink (filename))
3210 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
3211 GNUNET_free (set);
3212 return GNUNET_OK;
3213 }
3214 deserialize_download (h, rh, NULL, NULL, set);
3215 GNUNET_free (set);
3216 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
3217 {
3218 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3219 _ ("Failure while resuming download operation `%s': %s\n"),
3220 filename,
3221 emsg);
3222 GNUNET_free (emsg);
3223 }
3224 return GNUNET_OK;
3225}
3226
3227
3228/**
3229 * Deserialize information about pending operations.
3230 *
3231 * @param master_path which master directory should be scanned
3232 * @param proc function to call for each entry (will get @a h for 'cls')
3233 * @param h the `struct GNUNET_FS_Handle *`
3234 */
3235static void
3236deserialization_master (const char *master_path,
3237 GNUNET_FileNameCallback proc,
3238 struct GNUNET_FS_Handle *h)
3239{
3240 char *dn;
3241
3242 dn = get_serialization_file_name (h, master_path, "");
3243 if (NULL == dn)
3244 return;
3245 if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES))
3246 GNUNET_DISK_directory_scan (dn, proc, h);
3247 GNUNET_free (dn);
3248}
3249
3250
3251/**
3252 * Setup a connection to the file-sharing service.
3253 *
3254 * @param cfg configuration to use
3255 * @param client_name unique identifier for this client
3256 * @param upcb function to call to notify about FS actions
3257 * @param upcb_cls closure for @a upcb
3258 * @param flags specific attributes for fs-operations
3259 * @param ... list of optional options, terminated with #GNUNET_FS_OPTIONS_END
3260 * @return NULL on error
3261 */
3262struct GNUNET_FS_Handle *
3263GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
3264 const char *client_name,
3265 GNUNET_FS_ProgressCallback upcb,
3266 void *upcb_cls,
3267 enum GNUNET_FS_Flags flags,
3268 ...)
3269{
3270 struct GNUNET_FS_Handle *ret;
3271 enum GNUNET_FS_OPTIONS opt;
3272 va_list ap;
3273
3274 ret = GNUNET_new (struct GNUNET_FS_Handle);
3275 ret->cfg = cfg;
3276 ret->client_name = GNUNET_strdup (client_name);
3277 ret->upcb = upcb;
3278 ret->upcb_cls = upcb_cls;
3279 ret->flags = flags;
3280 ret->max_parallel_downloads = DEFAULT_MAX_PARALLEL_DOWNLOADS;
3281 ret->max_parallel_requests = DEFAULT_MAX_PARALLEL_REQUESTS;
3282 ret->avg_block_latency =
3283 GNUNET_TIME_UNIT_MINUTES; /* conservative starting point */
3284 va_start (ap, flags);
3285 while (GNUNET_FS_OPTIONS_END !=
3286 (opt = GNUNET_VA_ARG_ENUM (ap, GNUNET_FS_OPTIONS)))
3287 {
3288 switch (opt)
3289 {
3290 case GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM:
3291 ret->max_parallel_downloads = va_arg (ap, unsigned int);
3292
3293 break;
3294
3295 case GNUNET_FS_OPTIONS_REQUEST_PARALLELISM:
3296 ret->max_parallel_requests = va_arg (ap, unsigned int);
3297
3298 break;
3299
3300 default:
3301 GNUNET_break (0);
3302 GNUNET_free (ret->client_name);
3303 GNUNET_free (ret);
3304 va_end (ap);
3305 return NULL;
3306 }
3307 }
3308 va_end (ap);
3309 if (0 != (GNUNET_FS_FLAGS_PERSISTENCE & flags))
3310 {
3311 deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
3312 &deserialize_publish_file,
3313 ret);
3314 deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
3315 &deserialize_search_file,
3316 ret);
3317 deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
3318 &deserialize_download_file,
3319 ret);
3320 deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
3321 &deserialize_unindex_file,
3322 ret);
3323 }
3324 return ret;
3325}
3326
3327
3328/**
3329 * Close our connection with the file-sharing service.
3330 * The callback given to #GNUNET_FS_start() will no longer be
3331 * called after this function returns.
3332 * This function MUST NOT be called from within the
3333 * callback itself.
3334 *
3335 * @param h handle that was returned from #GNUNET_FS_start()
3336 */
3337void
3338GNUNET_FS_stop (struct GNUNET_FS_Handle *h)
3339{
3340 while (NULL != h->top_head)
3341 h->top_head->ssf (h->top_head->ssf_cls);
3342 if (NULL != h->queue_job)
3343 GNUNET_SCHEDULER_cancel (h->queue_job);
3344 GNUNET_free (h->client_name);
3345 GNUNET_free (h);
3346}
3347
3348
3349/* end of fs_api.c */