aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_unindex.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-08-22 17:57:31 +0000
committerChristian Grothoff <christian@grothoff.org>2009-08-22 17:57:31 +0000
commit2ae973618f3b51fa9bbf5532eaa1352cafc24ecc (patch)
treeea8bb13a4c7d390f88318b61bc6caf50ea6cf400 /src/fs/fs_unindex.c
parent9a10e9c06a3b08c8ab73edb7d2093a6d452ecc05 (diff)
downloadgnunet-2ae973618f3b51fa9bbf5532eaa1352cafc24ecc.tar.gz
gnunet-2ae973618f3b51fa9bbf5532eaa1352cafc24ecc.zip
stuff
Diffstat (limited to 'src/fs/fs_unindex.c')
-rw-r--r--src/fs/fs_unindex.c394
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 */
55static int
56pushBlock (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 */
108static int
109undoSymlinking (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 */
167int
168GNUNET_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;
384FAILURE:
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 */