aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fs/Makefile.am1
-rw-r--r--src/fs/fs.h137
-rw-r--r--src/fs/fs_list_indexed.c252
-rw-r--r--src/fs/fs_publish.c9
-rw-r--r--src/fs/fs_unindex.c687
-rw-r--r--src/include/gnunet_disk_lib.h12
-rw-r--r--src/include/gnunet_protocols.h10
-rw-r--r--src/util/disk.c5
8 files changed, 559 insertions, 554 deletions
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
index f1bc64784..ebe6790c9 100644
--- a/src/fs/Makefile.am
+++ b/src/fs/Makefile.am
@@ -19,6 +19,7 @@ libgnunetfs_la_SOURCES = \
19 fs_download.c \ 19 fs_download.c \
20 fs_file_information.c \ 20 fs_file_information.c \
21 fs_getopt.c \ 21 fs_getopt.c \
22 fs_list_indexed.c \
22 fs_publish.c \ 23 fs_publish.c \
23 fs_namespace.c \ 24 fs_namespace.c \
24 fs_search.c \ 25 fs_search.c \
diff --git a/src/fs/fs.h b/src/fs/fs.h
index 9fc15e62f..956048cc5 100644
--- a/src/fs/fs.h
+++ b/src/fs/fs.h
@@ -52,6 +52,15 @@
52#define MAX_INLINE_SIZE 65536 52#define MAX_INLINE_SIZE 65536
53 53
54 54
55/**
56 * Blocksize to use when hashing files
57 * for indexing (blocksize for IO, not for
58 * the DBlocks). Larger blocksizes can
59 * be more efficient but will be more disruptive
60 * as far as the scheduler is concerned.
61 */
62#define HASHING_BLOCKSIZE (1024 * 1024)
63
55 64
56/** 65/**
57 * @brief content hash key 66 * @brief content hash key
@@ -491,10 +500,106 @@ struct GNUNET_FS_PublishContext
491 500
492 501
493/** 502/**
503 * Phases of unindex processing (state machine).
504 */
505enum UnindexState
506 {
507 /**
508 * We're currently hashing the file.
509 */
510 UNINDEX_STATE_HASHING = 0,
511
512 /**
513 * We're notifying the FS service about
514 * the unindexing.
515 */
516 UNINDEX_STATE_FS_NOTIFY = 1,
517
518 /**
519 * We're telling the datastore to delete
520 * the respective entries.
521 */
522 UNINDEX_STATE_DS_REMOVE = 2,
523
524 /**
525 * We're done.
526 */
527 UNINDEX_STATE_COMPLETE = 3,
528
529 /**
530 * We've encountered a fatal error.
531 */
532 UNINDEX_STATE_ERROR = 4,
533
534 /**
535 * We've been aborted. The next callback should clean up the
536 * struct.
537 */
538 UNINDEX_STATE_ABORTED = 5
539 };
540
541
542/**
494 * Handle for controlling an unindexing operation. 543 * Handle for controlling an unindexing operation.
495 */ 544 */
496struct GNUNET_FS_UnindexContext 545struct GNUNET_FS_UnindexContext
497{ 546{
547
548 /**
549 * Global FS context.
550 */
551 struct GNUNET_FS_Handle *h;
552
553 /**
554 * Name of the file that we are unindexing.
555 */
556 char *filename;
557
558 /**
559 * Connection to the FS service,
560 * only valid during the UNINDEX_STATE_FS_NOTIFY
561 * phase.
562 */
563 struct GNUNET_CLIENT_Connection *client;
564
565 /**
566 * Connection to the datastore service,
567 * only valid during the UNINDEX_STATE_DS_NOTIFY
568 * phase.
569 */
570 struct GNUNET_DATASTORE_Handle *dsh;
571
572 /**
573 * Pointer kept for the client.
574 */
575 void *client_info;
576
577 /**
578 * Overall size of the file.
579 */
580 uint64_t file_size;
581
582 /**
583 * How far have we gotten?
584 */
585 uint64_t unindex_offset;
586
587 /**
588 * When did we start?
589 */
590 struct GNUNET_TIME_Absolute start_time;
591
592 /**
593 * Hash of the file's contents (once
594 * computed).
595 */
596 GNUNET_HashCode file_id;
597
598 /**
599 * Current operatinonal phase.
600 */
601 enum UnindexState state;
602
498}; 603};
499 604
500 605
@@ -695,6 +800,38 @@ struct IndexInfoMessage
695}; 800};
696 801
697 802
803/**
804 * Message sent from a GNUnet (fs) unindexing
805 * activity to the gnunet-fs-service to
806 * indicate that a file will be unindexed. The service
807 * is supposed to remove the file from the
808 * list of indexed files and response with
809 * a confirmation message (even if the file
810 * was already not on the list).
811 */
812struct UnindexMessage
813{
814
815 /**
816 * Message type will be
817 * GNUNET_MESSAGE_TYPE_FS_UNINDEX.
818 */
819 struct GNUNET_MessageHeader header;
820
821 /**
822 * Always zero.
823 */
824 uint32_t reserved;
825
826 /**
827 * Hash of the file that we will unindex.
828 */
829 GNUNET_HashCode file_id;
830
831};
832
833
834
698#endif 835#endif
699 836
700/* end of fs.h */ 837/* end of fs.h */
diff --git a/src/fs/fs_list_indexed.c b/src/fs/fs_list_indexed.c
new file mode 100644
index 000000000..1a404a078
--- /dev/null
+++ b/src/fs/fs_list_indexed.c
@@ -0,0 +1,252 @@
1/*
2 This file is part of GNUnet.
3 (C) 2003, 2004, 2006, 2009 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 2, 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_list_indexed.c
23 * @author Christian Grothoff
24 * @brief provide a list of all indexed files
25 */
26
27#include "platform.h"
28#include "gnunet_constants.h"
29#include "gnunet_fs_service.h"
30#include "gnunet_protocols.h"
31#include "fs.h"
32
33
34/**
35 * Context for "GNUNET_FS_get_indexed_files".
36 */
37struct GetIndexedContext
38{
39 /**
40 * Handle to global FS context.
41 */
42 struct GNUNET_FS_Handle *h;
43
44 /**
45 * Connection to the FS service.
46 */
47 struct GNUNET_CLIENT_Connection *client;
48
49 /**
50 * Function to call for each indexed file.
51 */
52 GNUNET_FS_IndexedFileProcessor iterator;
53
54 /**
55 * Closure for iterator.
56 */
57 void *iterator_cls;
58
59 /**
60 * Continuation to trigger at the end.
61 */
62 GNUNET_SCHEDULER_Task cont;
63
64 /**
65 * Closure for cont.
66 */
67 void *cont_cls;
68};
69
70
71/**
72 * Function called on each response from the FS
73 * service with information about indexed files.
74 *
75 * @param cls closure (of type "struct GetIndexedContext*")
76 * @param msg message with indexing information
77 */
78static void
79handle_index_info (void *cls,
80 const struct GNUNET_MessageHeader *msg)
81{
82 struct GetIndexedContext *gic = cls;
83 const struct IndexInfoMessage *iim;
84 uint16_t msize;
85 const char *filename;
86
87 if (NULL == msg)
88 {
89 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
90 _("Failed to receive response for `%s' request from `%s' service.\n"),
91 "GET_INDEXED",
92 "fs");
93 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
94 GNUNET_NO,
95 gic->cont,
96 gic->cont_cls,
97 GNUNET_SCHEDULER_REASON_TIMEOUT);
98 GNUNET_CLIENT_disconnect (gic->client);
99 GNUNET_free (gic);
100 return;
101 }
102 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END)
103 {
104 /* normal end-of-list */
105 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
106 GNUNET_NO,
107 gic->cont,
108 gic->cont_cls,
109 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
110 GNUNET_CLIENT_disconnect (gic->client);
111 GNUNET_free (gic);
112 return;
113 }
114 msize = ntohs (msg->size);
115 iim = (const struct IndexInfoMessage*) msg;
116 filename = (const char*) &iim[1];
117 if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY) ||
118 (msize <= sizeof (struct IndexInfoMessage)) ||
119 (filename[msize-sizeof (struct IndexInfoMessage) -1] != '\0') )
120 {
121 /* bogus reply */
122 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
123 _("Failed to receive valid response for `%s' request from `%s' service.\n"),
124 "GET_INDEXED",
125 "fs");
126 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
127 GNUNET_NO,
128 gic->cont,
129 gic->cont_cls,
130 GNUNET_SCHEDULER_REASON_TIMEOUT);
131 GNUNET_CLIENT_disconnect (gic->client);
132 GNUNET_free (gic);
133 return;
134 }
135 if (GNUNET_OK !=
136 gic->iterator (gic->iterator_cls,
137 filename,
138 &iim->file_id))
139 {
140 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
141 GNUNET_NO,
142 gic->cont,
143 gic->cont_cls,
144 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
145 GNUNET_CLIENT_disconnect (gic->client);
146 GNUNET_free (gic);
147 return;
148 }
149 /* get more */
150 GNUNET_CLIENT_receive (gic->client,
151 &handle_index_info,
152 gic,
153 GNUNET_CONSTANTS_SERVICE_TIMEOUT);
154}
155
156
157/**
158 * Transmit the request to get a list of all
159 * indexed files to the "FS" service.
160 *
161 * @param cls closure (of type "struct GetIndexedContext*")
162 * @param size number of bytes availabe in buf
163 * @param buf where to write the message, NULL on error
164 * @return number of bytes written to buf
165 */
166static size_t
167transmit_get_indexed (void *cls,
168 size_t size,
169 void *buf)
170{
171 struct GetIndexedContext *gic = cls;
172 struct GNUNET_MessageHeader *hdr;
173
174 if (NULL == buf)
175 {
176 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
177 _("Failed to transmit `%s' request to `%s' service.\n"),
178 "GET_INDEXED",
179 "fs");
180 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
181 GNUNET_NO,
182 gic->cont,
183 gic->cont_cls,
184 GNUNET_SCHEDULER_REASON_TIMEOUT);
185 GNUNET_CLIENT_disconnect (gic->client);
186 GNUNET_free (gic);
187 return 0;
188 }
189 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
190 hdr = buf;
191 hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
192 hdr->type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET);
193 GNUNET_CLIENT_receive (gic->client,
194 &handle_index_info,
195 gic,
196 GNUNET_CONSTANTS_SERVICE_TIMEOUT);
197 return sizeof (struct GNUNET_MessageHeader);
198}
199
200
201/**
202 * Iterate over all indexed files.
203 *
204 * @param h handle to the file sharing subsystem
205 * @param iterator function to call on each indexed file
206 * @param iterator_cls closure for iterator
207 * @param cont continuation to call when done;
208 * reason should be "TIMEOUT" (on
209 * error) or "PREREQ_DONE" (on success)
210 * @param cont_cls closure for cont
211 */
212void
213GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h,
214 GNUNET_FS_IndexedFileProcessor iterator,
215 void *iterator_cls,
216 GNUNET_SCHEDULER_Task cont,
217 void *cont_cls)
218{
219 struct GNUNET_CLIENT_Connection *client;
220 struct GetIndexedContext *gic;
221
222 client = GNUNET_CLIENT_connect (h->sched,
223 "fs",
224 h->cfg);
225 if (NULL == client)
226 {
227 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
228 _("Failed to not connect to `%s' service.\n"),
229 "fs");
230 GNUNET_SCHEDULER_add_continuation (h->sched,
231 GNUNET_NO,
232 cont,
233 cont_cls,
234 GNUNET_SCHEDULER_REASON_TIMEOUT);
235 return;
236 }
237
238 gic = GNUNET_malloc (sizeof (struct GetIndexedContext));
239 gic->h = h;
240 gic->client = client;
241 gic->iterator = iterator;
242 gic->iterator_cls = iterator_cls;
243 gic->cont = cont;
244 gic->cont_cls = cont_cls;
245 GNUNET_CLIENT_notify_transmit_ready (client,
246 sizeof (struct GNUNET_MessageHeader),
247 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
248 &transmit_get_indexed,
249 gic);
250}
251
252/* end of fs_list_indexed.c */
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c
index 13ce4d5aa..0c950f38a 100644
--- a/src/fs/fs_publish.c
+++ b/src/fs/fs_publish.c
@@ -53,15 +53,6 @@
53#define MAX_SBLOCK_SIZE 60000 53#define MAX_SBLOCK_SIZE 60000
54 54
55/** 55/**
56 * Blocksize to use when hashing files
57 * for indexing (blocksize for IO, not for
58 * the DBlocks). Larger blocksizes can
59 * be more efficient but will be more disruptive
60 * as far as the scheduler is concerned.
61 */
62#define HASHING_BLOCKSIZE (1024 * 1024)
63
64/**
65 * Main function that performs the upload. 56 * Main function that performs the upload.
66 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload 57 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload
67 * @param tc task context 58 * @param tc task context
diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c
index 8f09c44f6..9f1caac3a 100644
--- a/src/fs/fs_unindex.c
+++ b/src/fs/fs_unindex.c
@@ -27,7 +27,6 @@
27 * TODO: 27 * TODO:
28 * - code cleanup (share more with upload.c) 28 * - code cleanup (share more with upload.c)
29 */ 29 */
30
31#include "platform.h" 30#include "platform.h"
32#include "gnunet_constants.h" 31#include "gnunet_constants.h"
33#include "gnunet_fs_service.h" 32#include "gnunet_fs_service.h"
@@ -35,222 +34,144 @@
35#include "fs.h" 34#include "fs.h"
36 35
37 36
37
38
38/** 39/**
39 * Context for "GNUNET_FS_get_indexed_files". 40 * Fill in all of the generic fields for
41 * an unindex event.
42 *
43 * @param pc structure to fill in
44 * @param sc overall unindex context
40 */ 45 */
41struct GetIndexedContext 46static void
47make_unindex_status (struct GNUNET_FS_ProgressInfo *pi,
48 struct GNUNET_FS_UnindexContext *uc)
42{ 49{
43 /** 50 pi->value.unindex.uc = uc;
44 * Handle to global FS context. 51 pi->value.unindex.cctx = uc->client_info;
45 */ 52 pi->value.unindex.filename = uc->filename;
46 struct GNUNET_FS_Handle *h; 53 pi->value.unindex.size = uc->file_size;
47 54 pi->value.unindex.eta
48 /** 55 = GNUNET_TIME_calculate_eta (uc->start_time,
49 * Connection to the FS service. 56 uc->unindex_offset,
50 */ 57 uc->file_size);
51 struct GNUNET_CLIENT_Connection *client; 58 pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (uc->start_time);
52 59 pi->value.publish.completed = uc->unindex_offset;
53 /** 60}
54 * Function to call for each indexed file.
55 */
56 GNUNET_FS_IndexedFileProcessor iterator;
57
58 /**
59 * Closure for iterator.
60 */
61 void *iterator_cls;
62 61
63 /**
64 * Continuation to trigger at the end.
65 */
66 GNUNET_SCHEDULER_Task cont;
67 62
68 /** 63/**
69 * Closure for cont. 64 * We've encountered an error during
70 */ 65 * unindexing. Signal the client.
71 void *cont_cls; 66 *
72}; 67 * @param uc context for the failed unindexing operation
68 * @param emsg the error message
69 */
70static void
71signal_unindex_error (struct GNUNET_FS_UnindexContext *uc,
72 const char *emsg)
73{
74 struct GNUNET_FS_ProgressInfo pi;
75
76 pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR;
77 make_unindex_status (&pi, uc);
78 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
79 pi.value.unindex.specifics.error.message = emsg;
80 uc->client_info
81 = uc->h->upcb (uc->h->upcb_cls,
82 &pi);
83}
73 84
74 85
75/** 86/**
76 * Function called on each response from the FS 87 * Function called with the response from the
77 * service with information about indexed files. 88 * FS service to our unindexing request.
78 * 89 *
79 * @param cls closure (of type "struct GetIndexedContext*") 90 * @param cls closure, unindex context
80 * @param msg message with indexing information 91 * @param msg NULL on timeout, otherwise the response
81 */ 92 */
82static void 93static void
83handle_index_info (void *cls, 94process_fs_response (void *cls,
84 const struct GNUNET_MessageHeader *msg) 95 const struct GNUNET_MessageHeader *msg)
85{ 96{
86 struct GetIndexedContext *gic = cls; 97 struct GNUNET_FS_UnindexContext *uc = cls;
87 const struct IndexInfoMessage *iim;
88 uint16_t msize;
89 const char *filename;
90 98
91 if (NULL == msg) 99 GNUNET_CLIENT_disconnect (uc->client);
100 uc->client = NULL;
101 if (uc->state != UNINDEX_STATE_FS_NOTIFY)
92 { 102 {
93 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 103 GNUNET_FS_unindex_stop (uc);
94 _("Failed to receive response for `%s' request from `%s' service.\n"),
95 "GET_INDEXED",
96 "fs");
97 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
98 GNUNET_NO,
99 gic->cont,
100 gic->cont_cls,
101 GNUNET_SCHEDULER_REASON_TIMEOUT);
102 GNUNET_CLIENT_disconnect (gic->client);
103 GNUNET_free (gic);
104 return; 104 return;
105 } 105 }
106 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END) 106 if (NULL == msg)
107 { 107 {
108 /* normal end-of-list */ 108 uc->state = UNINDEX_STATE_ERROR;
109 GNUNET_SCHEDULER_add_continuation (gic->h->sched, 109 signal_unindex_error (uc,
110 GNUNET_NO, 110 _("Timeout waiting for `fs' service."));
111 gic->cont,
112 gic->cont_cls,
113 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
114 GNUNET_CLIENT_disconnect (gic->client);
115 GNUNET_free (gic);
116 return; 111 return;
117 } 112 }
118 msize = ntohs (msg->size); 113 if (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK)
119 iim = (const struct IndexInfoMessage*) msg;
120 filename = (const char*) &iim[1];
121 if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY) ||
122 (msize <= sizeof (struct IndexInfoMessage)) ||
123 (filename[msize-sizeof (struct IndexInfoMessage) -1] != '\0') )
124 { 114 {
125 /* bogus reply */ 115 uc->state = UNINDEX_STATE_ERROR;
126 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 116 signal_unindex_error (uc,
127 _("Failed to receive valid response for `%s' request from `%s' service.\n"), 117 _("Invalid response from `fs' service."));
128 "GET_INDEXED", 118 return;
129 "fs");
130 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
131 GNUNET_NO,
132 gic->cont,
133 gic->cont_cls,
134 GNUNET_SCHEDULER_REASON_TIMEOUT);
135 GNUNET_CLIENT_disconnect (gic->client);
136 GNUNET_free (gic);
137 return;
138 } 119 }
139 if (GNUNET_OK != 120 uc->state = UNINDEX_STATE_DS_REMOVE;
140 gic->iterator (gic->iterator_cls, 121 uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg,
141 filename, 122 uc->h->sched);
142 &iim->file_id)) 123 if (NULL == uc->dsh)
143 { 124 {
144 GNUNET_SCHEDULER_add_continuation (gic->h->sched, 125 uc->state = UNINDEX_STATE_ERROR;
145 GNUNET_NO, 126 signal_unindex_error (uc,
146 gic->cont, 127 _("Failed to connect to `datastore' service."));
147 gic->cont_cls,
148 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
149 GNUNET_CLIENT_disconnect (gic->client);
150 GNUNET_free (gic);
151 return; 128 return;
152 } 129 }
153 /* get more */ 130
154 GNUNET_CLIENT_receive (gic->client, 131 // FIXME: call shared code with publishing...
155 &handle_index_info,
156 gic,
157 GNUNET_CONSTANTS_SERVICE_TIMEOUT);
158} 132}
159 133
160 134
161/** 135/**
162 * Transmit the request to get a list of all 136 * Function called once the hash of the file
163 * indexed files to the "FS" service. 137 * that is being unindexed has been computed.
164 * 138 *
165 * @param cls closure (of type "struct GetIndexedContext*") 139 * @param cls closure, unindex context
166 * @param size number of bytes availabe in buf 140 * @param file_id computed hash, NULL on error
167 * @param buf where to write the message, NULL on error
168 * @return number of bytes written to buf
169 */ 141 */
170static size_t 142static void
171transmit_get_indexed (void *cls, 143process_hash (void *cls,
172 size_t size, 144 const GNUNET_HashCode *file_id)
173 void *buf)
174{ 145{
175 struct GetIndexedContext *gic = cls; 146 struct GNUNET_FS_UnindexContext *uc = cls;
176 struct GNUNET_MessageHeader *hdr; 147 struct UnindexMessage req;
177 148
178 if (NULL == buf) 149 if (uc->state != UNINDEX_STATE_HASHING)
179 { 150 {
180 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 151 GNUNET_FS_unindex_stop (uc);
181 _("Failed to transmit `%s' request to `%s' service.\n"), 152 return;
182 "GET_INDEXED",
183 "fs");
184 GNUNET_SCHEDULER_add_continuation (gic->h->sched,
185 GNUNET_NO,
186 gic->cont,
187 gic->cont_cls,
188 GNUNET_SCHEDULER_REASON_TIMEOUT);
189 GNUNET_CLIENT_disconnect (gic->client);
190 GNUNET_free (gic);
191 return 0;
192 } 153 }
193 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); 154 if (file_id == NULL)
194 hdr = buf;
195 hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
196 hdr->type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET);
197 GNUNET_CLIENT_receive (gic->client,
198 &handle_index_info,
199 gic,
200 GNUNET_CONSTANTS_SERVICE_TIMEOUT);
201 return sizeof (struct GNUNET_MessageHeader);
202}
203
204
205/**
206 * Iterate over all indexed files.
207 *
208 * @param h handle to the file sharing subsystem
209 * @param iterator function to call on each indexed file
210 * @param iterator_cls closure for iterator
211 * @param cont continuation to call when done;
212 * reason should be "TIMEOUT" (on
213 * error) or "PREREQ_DONE" (on success)
214 * @param cont_cls closure for cont
215 */
216void
217GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h,
218 GNUNET_FS_IndexedFileProcessor iterator,
219 void *iterator_cls,
220 GNUNET_SCHEDULER_Task cont,
221 void *cont_cls)
222{
223 struct GNUNET_CLIENT_Connection *client;
224 struct GetIndexedContext *gic;
225
226 client = GNUNET_CLIENT_connect (h->sched,
227 "fs",
228 h->cfg);
229 if (NULL == client)
230 { 155 {
231 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 156 uc->state = UNINDEX_STATE_ERROR;
232 _("Failed to not connect to `%s' service.\n"), 157 signal_unindex_error (uc,
233 "fs"); 158 _("Failed to compute hash of file."));
234 GNUNET_SCHEDULER_add_continuation (h->sched,
235 GNUNET_NO,
236 cont,
237 cont_cls,
238 GNUNET_SCHEDULER_REASON_TIMEOUT);
239 return; 159 return;
240 } 160 }
241 161 uc->file_id = *file_id;
242 gic = GNUNET_malloc (sizeof (struct GetIndexedContext)); 162 uc->state = UNINDEX_STATE_FS_NOTIFY;
243 gic->h = h; 163 uc->client = GNUNET_CLIENT_connect (uc->h->sched,
244 gic->client = client; 164 "fs",
245 gic->iterator = iterator; 165 uc->h->cfg);
246 gic->iterator_cls = iterator_cls; 166 req.header.size = htons (sizeof (struct UnindexMessage));
247 gic->cont = cont; 167 req.header.type = htons (GNUNET_MESSAGE_TYPE_FS_UNINDEX);
248 gic->cont_cls = cont_cls; 168 req.reserved = 0;
249 GNUNET_CLIENT_notify_transmit_ready (client, 169 req.file_id = *file_id;
250 sizeof (struct GNUNET_MessageHeader), 170 GNUNET_CLIENT_transmit_and_get_response (uc->client,
251 GNUNET_CONSTANTS_SERVICE_TIMEOUT, 171 &req.header,
252 &transmit_get_indexed, 172 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
253 gic); 173 &process_fs_response,
174 uc);
254} 175}
255 176
256 177
@@ -265,10 +186,36 @@ struct GNUNET_FS_UnindexContext *
265GNUNET_FS_unindex (struct GNUNET_FS_Handle *h, 186GNUNET_FS_unindex (struct GNUNET_FS_Handle *h,
266 const char *filename) 187 const char *filename)
267{ 188{
268 // 1: compute file-id (hash over entire file) 189 struct GNUNET_FS_UnindexContext *ret;
269 // 2: notify FS service about file no longer being indexed 190 struct GNUNET_FS_ProgressInfo pi;
270 // 3: remove corresponding blocks from datastore! 191 uint64_t size;
271 return NULL; 192
193 if (GNUNET_OK !=
194 GNUNET_DISK_file_size (filename,
195 &size,
196 GNUNET_YES))
197 return NULL;
198 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext));
199 ret->h = h;
200 ret->filename = GNUNET_strdup (filename);
201 ret->start_time = GNUNET_TIME_absolute_get ();
202 ret->file_size = size;
203
204 // FIXME: make persistent!
205 pi.status = GNUNET_FS_STATUS_UNINDEX_START;
206 make_unindex_status (&pi, ret);
207 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
208 ret->client_info
209 = h->upcb (h->upcb_cls,
210 &pi);
211 GNUNET_CRYPTO_hash_file (h->sched,
212 GNUNET_SCHEDULER_PRIORITY_IDLE,
213 GNUNET_NO,
214 filename,
215 HASHING_BLOCKSIZE,
216 &process_hash,
217 ret);
218 return ret;
272} 219}
273 220
274 221
@@ -279,365 +226,25 @@ GNUNET_FS_unindex (struct GNUNET_FS_Handle *h,
279 */ 226 */
280void 227void
281GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc) 228GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
282{ 229{
283} 230 struct GNUNET_FS_ProgressInfo pi;
284
285
286
287#if 0
288
289#define STRICT_CHECKS GNUNET_NO
290
291/**
292 * Append the given key and query to the iblock[level].
293 * If iblock[level] is already full, compute its chk
294 * and push it to level+1. iblocks is guaranteed to
295 * be big enough.
296 *
297 * This function matches exactly upload.c::pushBlock,
298 * except in the call to 'GNUNET_FS_delete'. TODO: refactor
299 * to avoid code duplication (move to block.c, pass
300 * GNUNET_FS_delete as argument!).
301 */
302static int
303pushBlock (struct GNUNET_ClientServerConnection *sock,
304 const GNUNET_EC_ContentHashKey * chk, unsigned int level,
305 GNUNET_DatastoreValue ** iblocks)
306{
307 unsigned int size;
308 unsigned int present;
309 GNUNET_DatastoreValue *value;
310 GNUNET_EC_DBlock *db;
311 GNUNET_EC_ContentHashKey ichk;
312 231
313 size = ntohl (iblocks[level]->size) - sizeof (GNUNET_DatastoreValue); 232 if ( (uc->state != UNINDEX_STATE_COMPLETE) &&
314 present = 233 (uc->state != UNINDEX_STATE_ERROR) )
315 (size - sizeof (GNUNET_EC_DBlock)) / sizeof (GNUNET_EC_ContentHashKey);
316 db = (GNUNET_EC_DBlock *) & iblocks[level][1];
317 if (present == GNUNET_ECRS_CHK_PER_INODE)
318 { 234 {
319 GNUNET_EC_file_block_get_key (db, size, &ichk.key); 235 uc->state = UNINDEX_STATE_ABORTED;
320 GNUNET_EC_file_block_get_query (db, size, &ichk.query); 236 return;
321 if (GNUNET_OK != pushBlock (sock, &ichk, level + 1, iblocks))
322 {
323 GNUNET_GE_BREAK (NULL, 0);
324 return GNUNET_SYSERR;
325 }
326 GNUNET_EC_file_block_encode (db, size, &ichk.query, &value);
327#if STRICT_CHECKS
328 if (GNUNET_SYSERR == GNUNET_FS_delete (sock, value))
329 {
330 GNUNET_free (value);
331 GNUNET_GE_BREAK (NULL, 0);
332 return GNUNET_SYSERR;
333 }
334#else
335 GNUNET_FS_delete (sock, value);
336#endif
337 GNUNET_free (value);
338 size = sizeof (GNUNET_EC_DBlock);
339 }
340 /* append GNUNET_EC_ContentHashKey */
341 memcpy (&((char *) db)[size], chk, sizeof (GNUNET_EC_ContentHashKey));
342 iblocks[level]->size = htonl (size +
343 sizeof (GNUNET_EC_ContentHashKey) +
344 sizeof (GNUNET_DatastoreValue));
345 return GNUNET_OK;
346}
347
348
349
350/**
351 * Undo sym-linking operation:
352 * a) check if we have a symlink
353 * b) delete symbolic link
354 */
355static int
356undoSymlinking (struct GNUNET_GE_Context *ectx,
357 const char *fn,
358 const GNUNET_HashCode * fileId,
359 struct GNUNET_ClientServerConnection *sock)
360{
361 GNUNET_EncName enc;
362 char *serverDir;
363 char *serverFN;
364 struct stat buf;
365
366#ifndef S_ISLNK
367 if (1)
368 return GNUNET_OK; /* symlinks do not exist? */
369#endif
370 if (0 != LSTAT (fn, &buf))
371 {
372 GNUNET_GE_LOG_STRERROR_FILE (ectx,
373 GNUNET_GE_ERROR | GNUNET_GE_BULK |
374 GNUNET_GE_USER | GNUNET_GE_ADMIN, "stat",
375 fn);
376 return GNUNET_SYSERR;
377 }
378#ifdef S_ISLNK
379 if (!S_ISLNK (buf.st_mode))
380 return GNUNET_OK;
381#endif
382 serverDir =
383 GNUNET_get_daemon_configuration_value (sock, "FS", "INDEX-DIRECTORY");
384 if (serverDir == NULL)
385 return GNUNET_OK;
386 serverFN = GNUNET_malloc (strlen (serverDir) + 2 + sizeof (GNUNET_EncName));
387 strcpy (serverFN, serverDir);
388 GNUNET_free (serverDir);
389 if (serverFN[strlen (serverFN) - 1] != DIR_SEPARATOR)
390 strcat (serverFN, DIR_SEPARATOR_STR);
391 GNUNET_hash_to_enc (fileId, &enc);
392 strcat (serverFN, (char *) &enc);
393
394 if (0 != UNLINK (serverFN))
395 {
396 GNUNET_GE_LOG_STRERROR_FILE (ectx,
397 GNUNET_GE_ERROR | GNUNET_GE_BULK |
398 GNUNET_GE_USER | GNUNET_GE_ADMIN, "unlink",
399 serverFN);
400 GNUNET_free (serverFN);
401 return GNUNET_SYSERR;
402 }
403 GNUNET_free (serverFN);
404 return GNUNET_OK;
405}
406
407
408
409/**
410 * Unindex a file.
411 *
412 * @return GNUNET_SYSERR if the unindexing failed (i.e. not indexed)
413 */
414int
415GNUNET_ECRS_file_unindex (struct GNUNET_GE_Context *ectx,
416 struct GNUNET_GC_Configuration *cfg,
417 const char *filename,
418 GNUNET_ECRS_UploadProgressCallback upcb,
419 void *upcbClosure, GNUNET_ECRS_TestTerminate tt,
420 void *ttClosure)
421{
422 unsigned long long filesize;
423 unsigned long long pos;
424 unsigned int treedepth;
425 int fd;
426 int i;
427 unsigned int size;
428 GNUNET_DatastoreValue **iblocks;
429 GNUNET_DatastoreValue *dblock;
430 GNUNET_EC_DBlock *db;
431 GNUNET_DatastoreValue *value;
432 struct GNUNET_ClientServerConnection *sock;
433 GNUNET_HashCode fileId;
434 GNUNET_EC_ContentHashKey chk;
435 GNUNET_CronTime eta;
436 GNUNET_CronTime start;
437 GNUNET_CronTime now;
438 int wasIndexed;
439
440 start = GNUNET_get_time ();
441 if (GNUNET_YES != GNUNET_disk_file_test (ectx, filename))
442 {
443 GNUNET_GE_BREAK (ectx, 0);
444 return GNUNET_SYSERR;
445 }
446 if (GNUNET_OK !=
447 GNUNET_disk_file_size (ectx, filename, &filesize, GNUNET_YES))
448 return GNUNET_SYSERR;
449 sock = GNUNET_client_connection_create (ectx, cfg);
450 if (sock == NULL)
451 return GNUNET_SYSERR;
452 eta = 0;
453 if (upcb != NULL)
454 upcb (filesize, 0, eta, upcbClosure);
455 if (GNUNET_SYSERR == GNUNET_hash_file (ectx, filename, &fileId))
456 {
457 GNUNET_client_connection_destroy (sock);
458 GNUNET_GE_BREAK (ectx, 0);
459 return GNUNET_SYSERR;
460 }
461 now = GNUNET_get_time ();
462 eta = now + 2 * (now - start);
463 /* very rough estimate: GNUNET_hash reads once through the file,
464 we'll do that once more and write it. But of course
465 the second read may be cached, and we have the encryption,
466 so a factor of two is really, really just a rough estimate */
467 start = now;
468 /* reset the counter since the formula later does not
469 take the time for GNUNET_hash_file into account */
470 treedepth = GNUNET_ECRS_compute_depth (filesize);
471
472 /* Test if file is indexed! */
473 wasIndexed = GNUNET_FS_test_indexed (sock, &fileId);
474
475 fd = GNUNET_disk_file_open (ectx, filename, O_RDONLY | O_LARGEFILE);
476 if (fd == -1)
477 {
478 GNUNET_client_connection_destroy (sock);
479 return GNUNET_SYSERR;
480 }
481 dblock =
482 GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE +
483 sizeof (GNUNET_EC_DBlock));
484 dblock->size =
485 htonl (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE +
486 sizeof (GNUNET_EC_DBlock));
487 dblock->anonymity_level = htonl (0);
488 dblock->priority = htonl (0);
489 dblock->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
490 dblock->expiration_time = GNUNET_htonll (0);
491 db = (GNUNET_EC_DBlock *) & dblock[1];
492 db->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
493 iblocks =
494 GNUNET_malloc (sizeof (GNUNET_DatastoreValue *) * (treedepth + 1));
495 for (i = 0; i <= treedepth; i++)
496 {
497 iblocks[i] =
498 GNUNET_malloc (sizeof (GNUNET_DatastoreValue) +
499 GNUNET_ECRS_IBLOCK_SIZE + sizeof (GNUNET_EC_DBlock));
500 iblocks[i]->size =
501 htonl (sizeof (GNUNET_DatastoreValue) + sizeof (GNUNET_EC_DBlock));
502 iblocks[i]->anonymity_level = htonl (0);
503 iblocks[i]->priority = htonl (0);
504 iblocks[i]->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
505 iblocks[i]->expiration_time = GNUNET_htonll (0);
506 ((GNUNET_EC_DBlock *) & iblocks[i][1])->type =
507 htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
508 }
509
510 pos = 0;
511 while (pos < filesize)
512 {
513 if (upcb != NULL)
514 upcb (filesize, pos, eta, upcbClosure);
515 if (tt != NULL)
516 if (GNUNET_OK != tt (ttClosure))
517 goto FAILURE;
518 size = GNUNET_ECRS_DBLOCK_SIZE;
519 if (size > filesize - pos)
520 {
521 size = filesize - pos;
522 memset (&db[1], 0, GNUNET_ECRS_DBLOCK_SIZE);
523 }
524 dblock->size =
525 htonl (sizeof (GNUNET_DatastoreValue) + size +
526 sizeof (GNUNET_EC_DBlock));
527 if (size != READ (fd, &db[1], size))
528 {
529 GNUNET_GE_LOG_STRERROR_FILE (ectx,
530 GNUNET_GE_ERROR | GNUNET_GE_USER |
531 GNUNET_GE_ADMIN | GNUNET_GE_BULK,
532 "READ", filename);
533 goto FAILURE;
534 }
535 if (tt != NULL)
536 if (GNUNET_OK != tt (ttClosure))
537 goto FAILURE;
538 GNUNET_EC_file_block_get_key (db, size + sizeof (GNUNET_EC_DBlock),
539 &chk.key);
540 GNUNET_EC_file_block_get_query (db, size + sizeof (GNUNET_EC_DBlock),
541 &chk.query);
542 if (GNUNET_OK != pushBlock (sock, &chk, 0, /* dblocks are on level 0 */
543 iblocks))
544 {
545 GNUNET_GE_BREAK (ectx, 0);
546 goto FAILURE;
547 }
548 if (!wasIndexed)
549 {
550 if (GNUNET_OK ==
551 GNUNET_EC_file_block_encode (db, size, &chk.query, &value))
552 {
553 *value = *dblock; /* copy options! */
554#if STRICT_CHECKS
555 if (GNUNET_OK != GNUNET_FS_delete (sock, value))
556 {
557 GNUNET_free (value);
558 GNUNET_GE_BREAK (ectx, 0);
559 goto FAILURE;
560 }
561#else
562 GNUNET_FS_delete (sock, value);
563#endif
564 GNUNET_free (value);
565 }
566 else
567 {
568 goto FAILURE;
569 }
570 }
571 pos += size;
572 now = GNUNET_get_time ();
573 eta = (GNUNET_CronTime) (start +
574 (((double) (now - start) / (double) pos))
575 * (double) filesize);
576 }
577 if (tt != NULL)
578 if (GNUNET_OK != tt (ttClosure))
579 goto FAILURE;
580 for (i = 0; i < treedepth; i++)
581 {
582 size = ntohl (iblocks[i]->size) - sizeof (GNUNET_DatastoreValue);
583 db = (GNUNET_EC_DBlock *) & iblocks[i][1];
584 GNUNET_EC_file_block_get_key (db, size, &chk.key);
585 GNUNET_EC_file_block_get_query (db, size, &chk.query);
586 if (GNUNET_OK != pushBlock (sock, &chk, i + 1, iblocks))
587 {
588 GNUNET_GE_BREAK (ectx, 0);
589 goto FAILURE;
590 }
591 GNUNET_EC_file_block_encode (db, size, &chk.query, &value);
592#if STRICT_CHECKS
593 if (GNUNET_OK != GNUNET_FS_delete (sock, value))
594 {
595 GNUNET_free (value);
596 GNUNET_GE_BREAK (ectx, 0);
597 goto FAILURE;
598 }
599#else
600 GNUNET_FS_delete (sock, value);
601#endif
602 GNUNET_free (value);
603 GNUNET_free (iblocks[i]);
604 iblocks[i] = NULL;
605 }
606
607 if (wasIndexed)
608 {
609 if (GNUNET_OK == undoSymlinking (ectx, filename, &fileId, sock))
610 {
611 if (GNUNET_OK !=
612 GNUNET_FS_unindex (sock, GNUNET_ECRS_DBLOCK_SIZE, &fileId))
613 {
614 GNUNET_GE_BREAK (ectx, 0);
615 goto FAILURE;
616 }
617 }
618 else
619 {
620 GNUNET_GE_BREAK (ectx, 0);
621 goto FAILURE;
622 }
623 } 237 }
624 GNUNET_free (iblocks[treedepth]); 238 // FIXME: make unpersistent!
625 /* free resources */ 239 pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED;
626 GNUNET_free (iblocks); 240 make_unindex_status (&pi, uc);
627 GNUNET_free (dblock); 241 pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
628 CLOSE (fd); 242 uc->client_info
629 GNUNET_client_connection_destroy (sock); 243 = uc->h->upcb (uc->h->upcb_cls,
630 return GNUNET_OK; 244 &pi);
631FAILURE: 245 GNUNET_break (NULL == uc->client_info);
632 for (i = 0; i <= treedepth; i++) 246 GNUNET_free (uc->filename);
633 GNUNET_free_non_null (iblocks[i]); 247 GNUNET_free (uc);
634 GNUNET_free (iblocks);
635 GNUNET_free (dblock);
636 CLOSE (fd);
637 GNUNET_client_connection_destroy (sock);
638 return GNUNET_SYSERR;
639} 248}
640 249
641#endif
642
643/* end of fs_unindex.c */ 250/* end of fs_unindex.c */
diff --git a/src/include/gnunet_disk_lib.h b/src/include/gnunet_disk_lib.h
index a3ac30d7e..692507641 100644
--- a/src/include/gnunet_disk_lib.h
+++ b/src/include/gnunet_disk_lib.h
@@ -125,21 +125,27 @@ int GNUNET_DISK_file_test (const char *fil);
125 * @return the new position on success, GNUNET_SYSERR otherwise 125 * @return the new position on success, GNUNET_SYSERR otherwise
126 */ 126 */
127off_t 127off_t
128GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, off_t offset, 128GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h,
129 enum GNUNET_DISK_Seek whence); 129 off_t offset,
130 enum GNUNET_DISK_Seek whence);
130 131
131 132
132/** 133/**
133 * Get the size of the file (or directory) 134 * Get the size of the file (or directory)
134 * of the given file (in bytes). 135 * of the given file (in bytes).
135 * 136 *
137 * @param filename name of the file or directory
138 * @param size set to the size of the file (or,
139 * in the case of directories, the sum
140 * of all sizes of files in the directory)
136 * @param includeSymLinks should symbolic links be 141 * @param includeSymLinks should symbolic links be
137 * included? 142 * included?
138 * 143 *
139 * @return GNUNET_OK on success, GNUNET_SYSERR on error 144 * @return GNUNET_OK on success, GNUNET_SYSERR on error
140 */ 145 */
141int GNUNET_DISK_file_size (const char *filename, 146int GNUNET_DISK_file_size (const char *filename,
142 unsigned long long *size, int includeSymLinks); 147 uint64_t *size,
148 int includeSymLinks);
143 149
144 150
145/** 151/**
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 5a11f29e9..ad8e28bd1 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -399,6 +399,16 @@ extern "C"
399 */ 399 */
400#define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END 133 400#define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END 133
401 401
402/**
403 * Request from client to unindex a file.
404 */
405#define GNUNET_MESSAGE_TYPE_FS_UNINDEX 134
406
407/**
408 * Reply to client indicating unindex receipt.
409 */
410#define GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK 135
411
402 412
403/* 413/*
404 TODO: 414 TODO:
diff --git a/src/util/disk.c b/src/util/disk.c
index 412f8fb16..899299e07 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -71,7 +71,7 @@
71 71
72typedef struct 72typedef struct
73{ 73{
74 unsigned long long total; 74 uint64_t total;
75 int include_sym_links; 75 int include_sym_links;
76} GetFileSizeData; 76} GetFileSizeData;
77 77
@@ -176,7 +176,8 @@ GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, off_t offset,
176 */ 176 */
177int 177int
178GNUNET_DISK_file_size (const char *filename, 178GNUNET_DISK_file_size (const char *filename,
179 unsigned long long *size, int includeSymLinks) 179 uint64_t *size,
180 int includeSymLinks)
180{ 181{
181 GetFileSizeData gfsd; 182 GetFileSizeData gfsd;
182 int ret; 183 int ret;