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