2 This file is part of GNUnet.
3 (C) 2003, 2004, 2006 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file applications/fs/ecrs/unindex.c
23 * @author Krista Bennett
24 * @author Christian Grothoff
29 * - code cleanup (share more with upload.c)
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"
42 #define STRICT_CHECKS GNUNET_NO
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
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!).
56 pushBlock (struct GNUNET_ClientServerConnection *sock,
57 const GNUNET_EC_ContentHashKey * chk, unsigned int level,
58 GNUNET_DatastoreValue ** iblocks)
62 GNUNET_DatastoreValue *value;
64 GNUNET_EC_ContentHashKey ichk;
66 size = ntohl (iblocks[level]->size) - sizeof (GNUNET_DatastoreValue);
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)
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))
76 GNUNET_GE_BREAK (NULL, 0);
79 GNUNET_EC_file_block_encode (db, size, &ichk.query, &value);
81 if (GNUNET_SYSERR == GNUNET_FS_delete (sock, value))
84 GNUNET_GE_BREAK (NULL, 0);
88 GNUNET_FS_delete (sock, value);
91 size = sizeof (GNUNET_EC_DBlock);
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));
104 * Undo sym-linking operation:
105 * a) check if we have a symlink
106 * b) delete symbolic link
109 undoSymlinking (struct GNUNET_GE_Context *ectx,
111 const GNUNET_HashCode * fileId,
112 struct GNUNET_ClientServerConnection *sock)
121 return GNUNET_OK; /* symlinks do not exist? */
123 if (0 != LSTAT (fn, &buf))
125 GNUNET_GE_LOG_STRERROR_FILE (ectx,
126 GNUNET_GE_ERROR | GNUNET_GE_BULK |
127 GNUNET_GE_USER | GNUNET_GE_ADMIN, "stat",
129 return GNUNET_SYSERR;
132 if (!S_ISLNK (buf.st_mode))
136 GNUNET_get_daemon_configuration_value (sock, "FS", "INDEX-DIRECTORY");
137 if (serverDir == NULL)
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);
147 if (0 != UNLINK (serverFN))
149 GNUNET_GE_LOG_STRERROR_FILE (ectx,
150 GNUNET_GE_ERROR | GNUNET_GE_BULK |
151 GNUNET_GE_USER | GNUNET_GE_ADMIN, "unlink",
153 GNUNET_free (serverFN);
154 return GNUNET_SYSERR;
156 GNUNET_free (serverFN);
165 * @return GNUNET_SYSERR if the unindexing failed (i.e. not indexed)
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,
175 unsigned long long filesize;
176 unsigned long long pos;
177 unsigned int treedepth;
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;
189 GNUNET_CronTime start;
193 start = GNUNET_get_time ();
194 if (GNUNET_YES != GNUNET_disk_file_test (ectx, filename))
196 GNUNET_GE_BREAK (ectx, 0);
197 return GNUNET_SYSERR;
200 GNUNET_disk_file_size (ectx, filename, &filesize, GNUNET_YES))
201 return GNUNET_SYSERR;
202 sock = GNUNET_client_connection_create (ectx, cfg);
204 return GNUNET_SYSERR;
207 upcb (filesize, 0, eta, upcbClosure);
208 if (GNUNET_SYSERR == GNUNET_hash_file (ectx, filename, &fileId))
210 GNUNET_client_connection_destroy (sock);
211 GNUNET_GE_BREAK (ectx, 0);
212 return GNUNET_SYSERR;
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 */
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);
225 /* Test if file is indexed! */
226 wasIndexed = GNUNET_FS_test_indexed (sock, &fileId);
228 fd = GNUNET_disk_file_open (ectx, filename, O_RDONLY | O_LARGEFILE);
231 GNUNET_client_connection_destroy (sock);
232 return GNUNET_SYSERR;
235 GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE +
236 sizeof (GNUNET_EC_DBlock));
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);
247 GNUNET_malloc (sizeof (GNUNET_DatastoreValue *) * (treedepth + 1));
248 for (i = 0; i <= treedepth; i++)
251 GNUNET_malloc (sizeof (GNUNET_DatastoreValue) +
252 GNUNET_ECRS_IBLOCK_SIZE + sizeof (GNUNET_EC_DBlock));
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);
264 while (pos < filesize)
267 upcb (filesize, pos, eta, upcbClosure);
269 if (GNUNET_OK != tt (ttClosure))
271 size = GNUNET_ECRS_DBLOCK_SIZE;
272 if (size > filesize - pos)
274 size = filesize - pos;
275 memset (&db[1], 0, GNUNET_ECRS_DBLOCK_SIZE);
278 htonl (sizeof (GNUNET_DatastoreValue) + size +
279 sizeof (GNUNET_EC_DBlock));
280 if (size != READ (fd, &db[1], size))
282 GNUNET_GE_LOG_STRERROR_FILE (ectx,
283 GNUNET_GE_ERROR | GNUNET_GE_USER |
284 GNUNET_GE_ADMIN | GNUNET_GE_BULK,
289 if (GNUNET_OK != tt (ttClosure))
291 GNUNET_EC_file_block_get_key (db, size + sizeof (GNUNET_EC_DBlock),
293 GNUNET_EC_file_block_get_query (db, size + sizeof (GNUNET_EC_DBlock),
295 if (GNUNET_OK != pushBlock (sock, &chk, 0, /* dblocks are on level 0 */
298 GNUNET_GE_BREAK (ectx, 0);
304 GNUNET_EC_file_block_encode (db, size, &chk.query, &value))
306 *value = *dblock; /* copy options! */
308 if (GNUNET_OK != GNUNET_FS_delete (sock, value))
311 GNUNET_GE_BREAK (ectx, 0);
315 GNUNET_FS_delete (sock, value);
325 now = GNUNET_get_time ();
326 eta = (GNUNET_CronTime) (start +
327 (((double) (now - start) / (double) pos))
328 * (double) filesize);
331 if (GNUNET_OK != tt (ttClosure))
333 for (i = 0; i < treedepth; i++)
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))
341 GNUNET_GE_BREAK (ectx, 0);
344 GNUNET_EC_file_block_encode (db, size, &chk.query, &value);
346 if (GNUNET_OK != GNUNET_FS_delete (sock, value))
349 GNUNET_GE_BREAK (ectx, 0);
353 GNUNET_FS_delete (sock, value);
356 GNUNET_free (iblocks[i]);
362 if (GNUNET_OK == undoSymlinking (ectx, filename, &fileId, sock))
365 GNUNET_FS_unindex (sock, GNUNET_ECRS_DBLOCK_SIZE, &fileId))
367 GNUNET_GE_BREAK (ectx, 0);
373 GNUNET_GE_BREAK (ectx, 0);
377 GNUNET_free (iblocks[treedepth]);
379 GNUNET_free (iblocks);
380 GNUNET_free (dblock);
382 GNUNET_client_connection_destroy (sock);
385 for (i = 0; i <= treedepth; i++)
386 GNUNET_free_non_null (iblocks[i]);
387 GNUNET_free (iblocks);
388 GNUNET_free (dblock);
390 GNUNET_client_connection_destroy (sock);
391 return GNUNET_SYSERR;
394 /* end of unindex.c */