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