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