diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-08-31 21:14:22 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-08-31 21:14:22 +0000 |
commit | 5dc5c7268ba88e70e208dc5c0a43b19bf111aeb3 (patch) | |
tree | f91bd544f2e14d69b9eee907e172588651215a76 /src/fs/fs_unindex.c | |
parent | 32716cc62ae96040bde78dacabe18a556290f392 (diff) | |
download | gnunet-5dc5c7268ba88e70e208dc5c0a43b19bf111aeb3.tar.gz gnunet-5dc5c7268ba88e70e208dc5c0a43b19bf111aeb3.zip |
working on unindex
Diffstat (limited to 'src/fs/fs_unindex.c')
-rw-r--r-- | src/fs/fs_unindex.c | 687 |
1 files changed, 147 insertions, 540 deletions
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 | */ |
41 | struct GetIndexedContext | 46 | static void |
47 | make_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 | */ | ||
70 | static void | ||
71 | signal_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 | */ |
82 | static void | 93 | static void |
83 | handle_index_info (void *cls, | 94 | process_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 | */ |
170 | static size_t | 142 | static void |
171 | transmit_get_indexed (void *cls, | 143 | process_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 | */ | ||
216 | void | ||
217 | GNUNET_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 * | |||
265 | GNUNET_FS_unindex (struct GNUNET_FS_Handle *h, | 186 | GNUNET_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 | */ |
280 | void | 227 | void |
281 | GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc) | 228 | GNUNET_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 | */ | ||
302 | static int | ||
303 | pushBlock (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 | */ | ||
355 | static int | ||
356 | undoSymlinking (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 | */ | ||
414 | int | ||
415 | GNUNET_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); |
631 | FAILURE: | 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 */ |