diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-08-22 17:57:31 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-08-22 17:57:31 +0000 |
commit | 2ae973618f3b51fa9bbf5532eaa1352cafc24ecc (patch) | |
tree | ea8bb13a4c7d390f88318b61bc6caf50ea6cf400 /src/fs/fs_unindex.c | |
parent | 9a10e9c06a3b08c8ab73edb7d2093a6d452ecc05 (diff) | |
download | gnunet-2ae973618f3b51fa9bbf5532eaa1352cafc24ecc.tar.gz gnunet-2ae973618f3b51fa9bbf5532eaa1352cafc24ecc.zip |
stuff
Diffstat (limited to 'src/fs/fs_unindex.c')
-rw-r--r-- | src/fs/fs_unindex.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c new file mode 100644 index 000000000..ef63e798e --- /dev/null +++ b/src/fs/fs_unindex.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2003, 2004, 2006 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 applications/fs/ecrs/unindex.c | ||
23 | * @author Krista Bennett | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * Unindex file. | ||
27 | * | ||
28 | * TODO: | ||
29 | * - code cleanup (share more with upload.c) | ||
30 | */ | ||
31 | |||
32 | #include "platform.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_ecrs_lib.h" | ||
35 | #include "gnunet_fs_lib.h" | ||
36 | #include "gnunet_getoption_lib.h" | ||
37 | #include "ecrs_core.h" | ||
38 | #include "ecrs.h" | ||
39 | #include "fs.h" | ||
40 | #include "tree.h" | ||
41 | |||
42 | #define STRICT_CHECKS GNUNET_NO | ||
43 | |||
44 | /** | ||
45 | * Append the given key and query to the iblock[level]. | ||
46 | * If iblock[level] is already full, compute its chk | ||
47 | * and push it to level+1. iblocks is guaranteed to | ||
48 | * be big enough. | ||
49 | * | ||
50 | * This function matches exactly upload.c::pushBlock, | ||
51 | * except in the call to 'GNUNET_FS_delete'. TODO: refactor | ||
52 | * to avoid code duplication (move to block.c, pass | ||
53 | * GNUNET_FS_delete as argument!). | ||
54 | */ | ||
55 | static int | ||
56 | pushBlock (struct GNUNET_ClientServerConnection *sock, | ||
57 | const GNUNET_EC_ContentHashKey * chk, unsigned int level, | ||
58 | GNUNET_DatastoreValue ** iblocks) | ||
59 | { | ||
60 | unsigned int size; | ||
61 | unsigned int present; | ||
62 | GNUNET_DatastoreValue *value; | ||
63 | GNUNET_EC_DBlock *db; | ||
64 | GNUNET_EC_ContentHashKey ichk; | ||
65 | |||
66 | size = ntohl (iblocks[level]->size) - sizeof (GNUNET_DatastoreValue); | ||
67 | present = | ||
68 | (size - sizeof (GNUNET_EC_DBlock)) / sizeof (GNUNET_EC_ContentHashKey); | ||
69 | db = (GNUNET_EC_DBlock *) & iblocks[level][1]; | ||
70 | if (present == GNUNET_ECRS_CHK_PER_INODE) | ||
71 | { | ||
72 | GNUNET_EC_file_block_get_key (db, size, &ichk.key); | ||
73 | GNUNET_EC_file_block_get_query (db, size, &ichk.query); | ||
74 | if (GNUNET_OK != pushBlock (sock, &ichk, level + 1, iblocks)) | ||
75 | { | ||
76 | GNUNET_GE_BREAK (NULL, 0); | ||
77 | return GNUNET_SYSERR; | ||
78 | } | ||
79 | GNUNET_EC_file_block_encode (db, size, &ichk.query, &value); | ||
80 | #if STRICT_CHECKS | ||
81 | if (GNUNET_SYSERR == GNUNET_FS_delete (sock, value)) | ||
82 | { | ||
83 | GNUNET_free (value); | ||
84 | GNUNET_GE_BREAK (NULL, 0); | ||
85 | return GNUNET_SYSERR; | ||
86 | } | ||
87 | #else | ||
88 | GNUNET_FS_delete (sock, value); | ||
89 | #endif | ||
90 | GNUNET_free (value); | ||
91 | size = sizeof (GNUNET_EC_DBlock); | ||
92 | } | ||
93 | /* append GNUNET_EC_ContentHashKey */ | ||
94 | memcpy (&((char *) db)[size], chk, sizeof (GNUNET_EC_ContentHashKey)); | ||
95 | iblocks[level]->size = htonl (size + | ||
96 | sizeof (GNUNET_EC_ContentHashKey) + | ||
97 | sizeof (GNUNET_DatastoreValue)); | ||
98 | return GNUNET_OK; | ||
99 | } | ||
100 | |||
101 | |||
102 | |||
103 | /** | ||
104 | * Undo sym-linking operation: | ||
105 | * a) check if we have a symlink | ||
106 | * b) delete symbolic link | ||
107 | */ | ||
108 | static int | ||
109 | undoSymlinking (struct GNUNET_GE_Context *ectx, | ||
110 | const char *fn, | ||
111 | const GNUNET_HashCode * fileId, | ||
112 | struct GNUNET_ClientServerConnection *sock) | ||
113 | { | ||
114 | GNUNET_EncName enc; | ||
115 | char *serverDir; | ||
116 | char *serverFN; | ||
117 | struct stat buf; | ||
118 | |||
119 | #ifndef S_ISLNK | ||
120 | if (1) | ||
121 | return GNUNET_OK; /* symlinks do not exist? */ | ||
122 | #endif | ||
123 | if (0 != LSTAT (fn, &buf)) | ||
124 | { | ||
125 | GNUNET_GE_LOG_STRERROR_FILE (ectx, | ||
126 | GNUNET_GE_ERROR | GNUNET_GE_BULK | | ||
127 | GNUNET_GE_USER | GNUNET_GE_ADMIN, "stat", | ||
128 | fn); | ||
129 | return GNUNET_SYSERR; | ||
130 | } | ||
131 | #ifdef S_ISLNK | ||
132 | if (!S_ISLNK (buf.st_mode)) | ||
133 | return GNUNET_OK; | ||
134 | #endif | ||
135 | serverDir = | ||
136 | GNUNET_get_daemon_configuration_value (sock, "FS", "INDEX-DIRECTORY"); | ||
137 | if (serverDir == NULL) | ||
138 | return GNUNET_OK; | ||
139 | serverFN = GNUNET_malloc (strlen (serverDir) + 2 + sizeof (GNUNET_EncName)); | ||
140 | strcpy (serverFN, serverDir); | ||
141 | GNUNET_free (serverDir); | ||
142 | if (serverFN[strlen (serverFN) - 1] != DIR_SEPARATOR) | ||
143 | strcat (serverFN, DIR_SEPARATOR_STR); | ||
144 | GNUNET_hash_to_enc (fileId, &enc); | ||
145 | strcat (serverFN, (char *) &enc); | ||
146 | |||
147 | if (0 != UNLINK (serverFN)) | ||
148 | { | ||
149 | GNUNET_GE_LOG_STRERROR_FILE (ectx, | ||
150 | GNUNET_GE_ERROR | GNUNET_GE_BULK | | ||
151 | GNUNET_GE_USER | GNUNET_GE_ADMIN, "unlink", | ||
152 | serverFN); | ||
153 | GNUNET_free (serverFN); | ||
154 | return GNUNET_SYSERR; | ||
155 | } | ||
156 | GNUNET_free (serverFN); | ||
157 | return GNUNET_OK; | ||
158 | } | ||
159 | |||
160 | |||
161 | |||
162 | /** | ||
163 | * Unindex a file. | ||
164 | * | ||
165 | * @return GNUNET_SYSERR if the unindexing failed (i.e. not indexed) | ||
166 | */ | ||
167 | int | ||
168 | GNUNET_ECRS_file_unindex (struct GNUNET_GE_Context *ectx, | ||
169 | struct GNUNET_GC_Configuration *cfg, | ||
170 | const char *filename, | ||
171 | GNUNET_ECRS_UploadProgressCallback upcb, | ||
172 | void *upcbClosure, GNUNET_ECRS_TestTerminate tt, | ||
173 | void *ttClosure) | ||
174 | { | ||
175 | unsigned long long filesize; | ||
176 | unsigned long long pos; | ||
177 | unsigned int treedepth; | ||
178 | int fd; | ||
179 | int i; | ||
180 | unsigned int size; | ||
181 | GNUNET_DatastoreValue **iblocks; | ||
182 | GNUNET_DatastoreValue *dblock; | ||
183 | GNUNET_EC_DBlock *db; | ||
184 | GNUNET_DatastoreValue *value; | ||
185 | struct GNUNET_ClientServerConnection *sock; | ||
186 | GNUNET_HashCode fileId; | ||
187 | GNUNET_EC_ContentHashKey chk; | ||
188 | GNUNET_CronTime eta; | ||
189 | GNUNET_CronTime start; | ||
190 | GNUNET_CronTime now; | ||
191 | int wasIndexed; | ||
192 | |||
193 | start = GNUNET_get_time (); | ||
194 | if (GNUNET_YES != GNUNET_disk_file_test (ectx, filename)) | ||
195 | { | ||
196 | GNUNET_GE_BREAK (ectx, 0); | ||
197 | return GNUNET_SYSERR; | ||
198 | } | ||
199 | if (GNUNET_OK != | ||
200 | GNUNET_disk_file_size (ectx, filename, &filesize, GNUNET_YES)) | ||
201 | return GNUNET_SYSERR; | ||
202 | sock = GNUNET_client_connection_create (ectx, cfg); | ||
203 | if (sock == NULL) | ||
204 | return GNUNET_SYSERR; | ||
205 | eta = 0; | ||
206 | if (upcb != NULL) | ||
207 | upcb (filesize, 0, eta, upcbClosure); | ||
208 | if (GNUNET_SYSERR == GNUNET_hash_file (ectx, filename, &fileId)) | ||
209 | { | ||
210 | GNUNET_client_connection_destroy (sock); | ||
211 | GNUNET_GE_BREAK (ectx, 0); | ||
212 | return GNUNET_SYSERR; | ||
213 | } | ||
214 | now = GNUNET_get_time (); | ||
215 | eta = now + 2 * (now - start); | ||
216 | /* very rough estimate: GNUNET_hash reads once through the file, | ||
217 | we'll do that once more and write it. But of course | ||
218 | the second read may be cached, and we have the encryption, | ||
219 | so a factor of two is really, really just a rough estimate */ | ||
220 | start = now; | ||
221 | /* reset the counter since the formula later does not | ||
222 | take the time for GNUNET_hash_file into account */ | ||
223 | treedepth = GNUNET_ECRS_compute_depth (filesize); | ||
224 | |||
225 | /* Test if file is indexed! */ | ||
226 | wasIndexed = GNUNET_FS_test_indexed (sock, &fileId); | ||
227 | |||
228 | fd = GNUNET_disk_file_open (ectx, filename, O_RDONLY | O_LARGEFILE); | ||
229 | if (fd == -1) | ||
230 | { | ||
231 | GNUNET_client_connection_destroy (sock); | ||
232 | return GNUNET_SYSERR; | ||
233 | } | ||
234 | dblock = | ||
235 | GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE + | ||
236 | sizeof (GNUNET_EC_DBlock)); | ||
237 | dblock->size = | ||
238 | htonl (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE + | ||
239 | sizeof (GNUNET_EC_DBlock)); | ||
240 | dblock->anonymity_level = htonl (0); | ||
241 | dblock->priority = htonl (0); | ||
242 | dblock->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA); | ||
243 | dblock->expiration_time = GNUNET_htonll (0); | ||
244 | db = (GNUNET_EC_DBlock *) & dblock[1]; | ||
245 | db->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA); | ||
246 | iblocks = | ||
247 | GNUNET_malloc (sizeof (GNUNET_DatastoreValue *) * (treedepth + 1)); | ||
248 | for (i = 0; i <= treedepth; i++) | ||
249 | { | ||
250 | iblocks[i] = | ||
251 | GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + | ||
252 | GNUNET_ECRS_IBLOCK_SIZE + sizeof (GNUNET_EC_DBlock)); | ||
253 | iblocks[i]->size = | ||
254 | htonl (sizeof (GNUNET_DatastoreValue) + sizeof (GNUNET_EC_DBlock)); | ||
255 | iblocks[i]->anonymity_level = htonl (0); | ||
256 | iblocks[i]->priority = htonl (0); | ||
257 | iblocks[i]->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA); | ||
258 | iblocks[i]->expiration_time = GNUNET_htonll (0); | ||
259 | ((GNUNET_EC_DBlock *) & iblocks[i][1])->type = | ||
260 | htonl (GNUNET_ECRS_BLOCKTYPE_DATA); | ||
261 | } | ||
262 | |||
263 | pos = 0; | ||
264 | while (pos < filesize) | ||
265 | { | ||
266 | if (upcb != NULL) | ||
267 | upcb (filesize, pos, eta, upcbClosure); | ||
268 | if (tt != NULL) | ||
269 | if (GNUNET_OK != tt (ttClosure)) | ||
270 | goto FAILURE; | ||
271 | size = GNUNET_ECRS_DBLOCK_SIZE; | ||
272 | if (size > filesize - pos) | ||
273 | { | ||
274 | size = filesize - pos; | ||
275 | memset (&db[1], 0, GNUNET_ECRS_DBLOCK_SIZE); | ||
276 | } | ||
277 | dblock->size = | ||
278 | htonl (sizeof (GNUNET_DatastoreValue) + size + | ||
279 | sizeof (GNUNET_EC_DBlock)); | ||
280 | if (size != READ (fd, &db[1], size)) | ||
281 | { | ||
282 | GNUNET_GE_LOG_STRERROR_FILE (ectx, | ||
283 | GNUNET_GE_ERROR | GNUNET_GE_USER | | ||
284 | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | ||
285 | "READ", filename); | ||
286 | goto FAILURE; | ||
287 | } | ||
288 | if (tt != NULL) | ||
289 | if (GNUNET_OK != tt (ttClosure)) | ||
290 | goto FAILURE; | ||
291 | GNUNET_EC_file_block_get_key (db, size + sizeof (GNUNET_EC_DBlock), | ||
292 | &chk.key); | ||
293 | GNUNET_EC_file_block_get_query (db, size + sizeof (GNUNET_EC_DBlock), | ||
294 | &chk.query); | ||
295 | if (GNUNET_OK != pushBlock (sock, &chk, 0, /* dblocks are on level 0 */ | ||
296 | iblocks)) | ||
297 | { | ||
298 | GNUNET_GE_BREAK (ectx, 0); | ||
299 | goto FAILURE; | ||
300 | } | ||
301 | if (!wasIndexed) | ||
302 | { | ||
303 | if (GNUNET_OK == | ||
304 | GNUNET_EC_file_block_encode (db, size, &chk.query, &value)) | ||
305 | { | ||
306 | *value = *dblock; /* copy options! */ | ||
307 | #if STRICT_CHECKS | ||
308 | if (GNUNET_OK != GNUNET_FS_delete (sock, value)) | ||
309 | { | ||
310 | GNUNET_free (value); | ||
311 | GNUNET_GE_BREAK (ectx, 0); | ||
312 | goto FAILURE; | ||
313 | } | ||
314 | #else | ||
315 | GNUNET_FS_delete (sock, value); | ||
316 | #endif | ||
317 | GNUNET_free (value); | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | goto FAILURE; | ||
322 | } | ||
323 | } | ||
324 | pos += size; | ||
325 | now = GNUNET_get_time (); | ||
326 | eta = (GNUNET_CronTime) (start + | ||
327 | (((double) (now - start) / (double) pos)) | ||
328 | * (double) filesize); | ||
329 | } | ||
330 | if (tt != NULL) | ||
331 | if (GNUNET_OK != tt (ttClosure)) | ||
332 | goto FAILURE; | ||
333 | for (i = 0; i < treedepth; i++) | ||
334 | { | ||
335 | size = ntohl (iblocks[i]->size) - sizeof (GNUNET_DatastoreValue); | ||
336 | db = (GNUNET_EC_DBlock *) & iblocks[i][1]; | ||
337 | GNUNET_EC_file_block_get_key (db, size, &chk.key); | ||
338 | GNUNET_EC_file_block_get_query (db, size, &chk.query); | ||
339 | if (GNUNET_OK != pushBlock (sock, &chk, i + 1, iblocks)) | ||
340 | { | ||
341 | GNUNET_GE_BREAK (ectx, 0); | ||
342 | goto FAILURE; | ||
343 | } | ||
344 | GNUNET_EC_file_block_encode (db, size, &chk.query, &value); | ||
345 | #if STRICT_CHECKS | ||
346 | if (GNUNET_OK != GNUNET_FS_delete (sock, value)) | ||
347 | { | ||
348 | GNUNET_free (value); | ||
349 | GNUNET_GE_BREAK (ectx, 0); | ||
350 | goto FAILURE; | ||
351 | } | ||
352 | #else | ||
353 | GNUNET_FS_delete (sock, value); | ||
354 | #endif | ||
355 | GNUNET_free (value); | ||
356 | GNUNET_free (iblocks[i]); | ||
357 | iblocks[i] = NULL; | ||
358 | } | ||
359 | |||
360 | if (wasIndexed) | ||
361 | { | ||
362 | if (GNUNET_OK == undoSymlinking (ectx, filename, &fileId, sock)) | ||
363 | { | ||
364 | if (GNUNET_OK != | ||
365 | GNUNET_FS_unindex (sock, GNUNET_ECRS_DBLOCK_SIZE, &fileId)) | ||
366 | { | ||
367 | GNUNET_GE_BREAK (ectx, 0); | ||
368 | goto FAILURE; | ||
369 | } | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | GNUNET_GE_BREAK (ectx, 0); | ||
374 | goto FAILURE; | ||
375 | } | ||
376 | } | ||
377 | GNUNET_free (iblocks[treedepth]); | ||
378 | /* free resources */ | ||
379 | GNUNET_free (iblocks); | ||
380 | GNUNET_free (dblock); | ||
381 | CLOSE (fd); | ||
382 | GNUNET_client_connection_destroy (sock); | ||
383 | return GNUNET_OK; | ||
384 | FAILURE: | ||
385 | for (i = 0; i <= treedepth; i++) | ||
386 | GNUNET_free_non_null (iblocks[i]); | ||
387 | GNUNET_free (iblocks); | ||
388 | GNUNET_free (dblock); | ||
389 | CLOSE (fd); | ||
390 | GNUNET_client_connection_destroy (sock); | ||
391 | return GNUNET_SYSERR; | ||
392 | } | ||
393 | |||
394 | /* end of unindex.c */ | ||