aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_unindex.c
diff options
context:
space:
mode:
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 0000000000..ef63e798eb
--- /dev/null
+++ b/src/fs/fs_unindex.c
@@ -0,0 +1,394 @@
+/*
+ This file is part of GNUnet.
+ (C) 2003, 2004, 2006 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file applications/fs/ecrs/unindex.c
+ * @author Krista Bennett
+ * @author Christian Grothoff
+ *
+ * Unindex file.
+ *
+ * TODO:
+ * - code cleanup (share more with upload.c)
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_ecrs_lib.h"
+#include "gnunet_fs_lib.h"
+#include "gnunet_getoption_lib.h"
+#include "ecrs_core.h"
+#include "ecrs.h"
+#include "fs.h"
+#include "tree.h"
+
+#define STRICT_CHECKS GNUNET_NO
+
+/**
+ * Append the given key and query to the iblock[level].
+ * If iblock[level] is already full, compute its chk
+ * and push it to level+1. iblocks is guaranteed to
+ * be big enough.
+ *
+ * This function matches exactly upload.c::pushBlock,
+ * except in the call to 'GNUNET_FS_delete'. TODO: refactor
+ * to avoid code duplication (move to block.c, pass
+ * GNUNET_FS_delete as argument!).
+ */
+static int
+pushBlock (struct GNUNET_ClientServerConnection *sock,
+ const GNUNET_EC_ContentHashKey * chk, unsigned int level,
+ GNUNET_DatastoreValue ** iblocks)
+{
+ unsigned int size;
+ unsigned int present;
+ GNUNET_DatastoreValue *value;
+ GNUNET_EC_DBlock *db;
+ GNUNET_EC_ContentHashKey ichk;
+
+ size = ntohl (iblocks[level]->size) - sizeof (GNUNET_DatastoreValue);
+ present =
+ (size - sizeof (GNUNET_EC_DBlock)) / sizeof (GNUNET_EC_ContentHashKey);
+ db = (GNUNET_EC_DBlock *) & iblocks[level][1];
+ if (present == GNUNET_ECRS_CHK_PER_INODE)
+ {
+ GNUNET_EC_file_block_get_key (db, size, &ichk.key);
+ GNUNET_EC_file_block_get_query (db, size, &ichk.query);
+ if (GNUNET_OK != pushBlock (sock, &ichk, level + 1, iblocks))
+ {
+ GNUNET_GE_BREAK (NULL, 0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_EC_file_block_encode (db, size, &ichk.query, &value);
+#if STRICT_CHECKS
+ if (GNUNET_SYSERR == GNUNET_FS_delete (sock, value))
+ {
+ GNUNET_free (value);
+ GNUNET_GE_BREAK (NULL, 0);
+ return GNUNET_SYSERR;
+ }
+#else
+ GNUNET_FS_delete (sock, value);
+#endif
+ GNUNET_free (value);
+ size = sizeof (GNUNET_EC_DBlock);
+ }
+ /* append GNUNET_EC_ContentHashKey */
+ memcpy (&((char *) db)[size], chk, sizeof (GNUNET_EC_ContentHashKey));
+ iblocks[level]->size = htonl (size +
+ sizeof (GNUNET_EC_ContentHashKey) +
+ sizeof (GNUNET_DatastoreValue));
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Undo sym-linking operation:
+ * a) check if we have a symlink
+ * b) delete symbolic link
+ */
+static int
+undoSymlinking (struct GNUNET_GE_Context *ectx,
+ const char *fn,
+ const GNUNET_HashCode * fileId,
+ struct GNUNET_ClientServerConnection *sock)
+{
+ GNUNET_EncName enc;
+ char *serverDir;
+ char *serverFN;
+ struct stat buf;
+
+#ifndef S_ISLNK
+ if (1)
+ return GNUNET_OK; /* symlinks do not exist? */
+#endif
+ if (0 != LSTAT (fn, &buf))
+ {
+ GNUNET_GE_LOG_STRERROR_FILE (ectx,
+ GNUNET_GE_ERROR | GNUNET_GE_BULK |
+ GNUNET_GE_USER | GNUNET_GE_ADMIN, "stat",
+ fn);
+ return GNUNET_SYSERR;
+ }
+#ifdef S_ISLNK
+ if (!S_ISLNK (buf.st_mode))
+ return GNUNET_OK;
+#endif
+ serverDir =
+ GNUNET_get_daemon_configuration_value (sock, "FS", "INDEX-DIRECTORY");
+ if (serverDir == NULL)
+ return GNUNET_OK;
+ serverFN = GNUNET_malloc (strlen (serverDir) + 2 + sizeof (GNUNET_EncName));
+ strcpy (serverFN, serverDir);
+ GNUNET_free (serverDir);
+ if (serverFN[strlen (serverFN) - 1] != DIR_SEPARATOR)
+ strcat (serverFN, DIR_SEPARATOR_STR);
+ GNUNET_hash_to_enc (fileId, &enc);
+ strcat (serverFN, (char *) &enc);
+
+ if (0 != UNLINK (serverFN))
+ {
+ GNUNET_GE_LOG_STRERROR_FILE (ectx,
+ GNUNET_GE_ERROR | GNUNET_GE_BULK |
+ GNUNET_GE_USER | GNUNET_GE_ADMIN, "unlink",
+ serverFN);
+ GNUNET_free (serverFN);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (serverFN);
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Unindex a file.
+ *
+ * @return GNUNET_SYSERR if the unindexing failed (i.e. not indexed)
+ */
+int
+GNUNET_ECRS_file_unindex (struct GNUNET_GE_Context *ectx,
+ struct GNUNET_GC_Configuration *cfg,
+ const char *filename,
+ GNUNET_ECRS_UploadProgressCallback upcb,
+ void *upcbClosure, GNUNET_ECRS_TestTerminate tt,
+ void *ttClosure)
+{
+ unsigned long long filesize;
+ unsigned long long pos;
+ unsigned int treedepth;
+ int fd;
+ int i;
+ unsigned int size;
+ GNUNET_DatastoreValue **iblocks;
+ GNUNET_DatastoreValue *dblock;
+ GNUNET_EC_DBlock *db;
+ GNUNET_DatastoreValue *value;
+ struct GNUNET_ClientServerConnection *sock;
+ GNUNET_HashCode fileId;
+ GNUNET_EC_ContentHashKey chk;
+ GNUNET_CronTime eta;
+ GNUNET_CronTime start;
+ GNUNET_CronTime now;
+ int wasIndexed;
+
+ start = GNUNET_get_time ();
+ if (GNUNET_YES != GNUNET_disk_file_test (ectx, filename))
+ {
+ GNUNET_GE_BREAK (ectx, 0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_disk_file_size (ectx, filename, &filesize, GNUNET_YES))
+ return GNUNET_SYSERR;
+ sock = GNUNET_client_connection_create (ectx, cfg);
+ if (sock == NULL)
+ return GNUNET_SYSERR;
+ eta = 0;
+ if (upcb != NULL)
+ upcb (filesize, 0, eta, upcbClosure);
+ if (GNUNET_SYSERR == GNUNET_hash_file (ectx, filename, &fileId))
+ {
+ GNUNET_client_connection_destroy (sock);
+ GNUNET_GE_BREAK (ectx, 0);
+ return GNUNET_SYSERR;
+ }
+ now = GNUNET_get_time ();
+ eta = now + 2 * (now - start);
+ /* very rough estimate: GNUNET_hash reads once through the file,
+ we'll do that once more and write it. But of course
+ the second read may be cached, and we have the encryption,
+ so a factor of two is really, really just a rough estimate */
+ start = now;
+ /* reset the counter since the formula later does not
+ take the time for GNUNET_hash_file into account */
+ treedepth = GNUNET_ECRS_compute_depth (filesize);
+
+ /* Test if file is indexed! */
+ wasIndexed = GNUNET_FS_test_indexed (sock, &fileId);
+
+ fd = GNUNET_disk_file_open (ectx, filename, O_RDONLY | O_LARGEFILE);
+ if (fd == -1)
+ {
+ GNUNET_client_connection_destroy (sock);
+ return GNUNET_SYSERR;
+ }
+ dblock =
+ GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE +
+ sizeof (GNUNET_EC_DBlock));
+ dblock->size =
+ htonl (sizeof (GNUNET_DatastoreValue) + GNUNET_ECRS_DBLOCK_SIZE +
+ sizeof (GNUNET_EC_DBlock));
+ dblock->anonymity_level = htonl (0);
+ dblock->priority = htonl (0);
+ dblock->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
+ dblock->expiration_time = GNUNET_htonll (0);
+ db = (GNUNET_EC_DBlock *) & dblock[1];
+ db->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
+ iblocks =
+ GNUNET_malloc (sizeof (GNUNET_DatastoreValue *) * (treedepth + 1));
+ for (i = 0; i <= treedepth; i++)
+ {
+ iblocks[i] =
+ GNUNET_malloc (sizeof (GNUNET_DatastoreValue) +
+ GNUNET_ECRS_IBLOCK_SIZE + sizeof (GNUNET_EC_DBlock));
+ iblocks[i]->size =
+ htonl (sizeof (GNUNET_DatastoreValue) + sizeof (GNUNET_EC_DBlock));
+ iblocks[i]->anonymity_level = htonl (0);
+ iblocks[i]->priority = htonl (0);
+ iblocks[i]->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
+ iblocks[i]->expiration_time = GNUNET_htonll (0);
+ ((GNUNET_EC_DBlock *) & iblocks[i][1])->type =
+ htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
+ }
+
+ pos = 0;
+ while (pos < filesize)
+ {
+ if (upcb != NULL)
+ upcb (filesize, pos, eta, upcbClosure);
+ if (tt != NULL)
+ if (GNUNET_OK != tt (ttClosure))
+ goto FAILURE;
+ size = GNUNET_ECRS_DBLOCK_SIZE;
+ if (size > filesize - pos)
+ {
+ size = filesize - pos;
+ memset (&db[1], 0, GNUNET_ECRS_DBLOCK_SIZE);
+ }
+ dblock->size =
+ htonl (sizeof (GNUNET_DatastoreValue) + size +
+ sizeof (GNUNET_EC_DBlock));
+ if (size != READ (fd, &db[1], size))
+ {
+ GNUNET_GE_LOG_STRERROR_FILE (ectx,
+ GNUNET_GE_ERROR | GNUNET_GE_USER |
+ GNUNET_GE_ADMIN | GNUNET_GE_BULK,
+ "READ", filename);
+ goto FAILURE;
+ }
+ if (tt != NULL)
+ if (GNUNET_OK != tt (ttClosure))
+ goto FAILURE;
+ GNUNET_EC_file_block_get_key (db, size + sizeof (GNUNET_EC_DBlock),
+ &chk.key);
+ GNUNET_EC_file_block_get_query (db, size + sizeof (GNUNET_EC_DBlock),
+ &chk.query);
+ if (GNUNET_OK != pushBlock (sock, &chk, 0, /* dblocks are on level 0 */
+ iblocks))
+ {
+ GNUNET_GE_BREAK (ectx, 0);
+ goto FAILURE;
+ }
+ if (!wasIndexed)
+ {
+ if (GNUNET_OK ==
+ GNUNET_EC_file_block_encode (db, size, &chk.query, &value))
+ {
+ *value = *dblock; /* copy options! */
+#if STRICT_CHECKS
+ if (GNUNET_OK != GNUNET_FS_delete (sock, value))
+ {
+ GNUNET_free (value);
+ GNUNET_GE_BREAK (ectx, 0);
+ goto FAILURE;
+ }
+#else
+ GNUNET_FS_delete (sock, value);
+#endif
+ GNUNET_free (value);
+ }
+ else
+ {
+ goto FAILURE;
+ }
+ }
+ pos += size;
+ now = GNUNET_get_time ();
+ eta = (GNUNET_CronTime) (start +
+ (((double) (now - start) / (double) pos))
+ * (double) filesize);
+ }
+ if (tt != NULL)
+ if (GNUNET_OK != tt (ttClosure))
+ goto FAILURE;
+ for (i = 0; i < treedepth; i++)
+ {
+ size = ntohl (iblocks[i]->size) - sizeof (GNUNET_DatastoreValue);
+ db = (GNUNET_EC_DBlock *) & iblocks[i][1];
+ GNUNET_EC_file_block_get_key (db, size, &chk.key);
+ GNUNET_EC_file_block_get_query (db, size, &chk.query);
+ if (GNUNET_OK != pushBlock (sock, &chk, i + 1, iblocks))
+ {
+ GNUNET_GE_BREAK (ectx, 0);
+ goto FAILURE;
+ }
+ GNUNET_EC_file_block_encode (db, size, &chk.query, &value);
+#if STRICT_CHECKS
+ if (GNUNET_OK != GNUNET_FS_delete (sock, value))
+ {
+ GNUNET_free (value);
+ GNUNET_GE_BREAK (ectx, 0);
+ goto FAILURE;
+ }
+#else
+ GNUNET_FS_delete (sock, value);
+#endif
+ GNUNET_free (value);
+ GNUNET_free (iblocks[i]);
+ iblocks[i] = NULL;
+ }
+
+ if (wasIndexed)
+ {
+ if (GNUNET_OK == undoSymlinking (ectx, filename, &fileId, sock))
+ {
+ if (GNUNET_OK !=
+ GNUNET_FS_unindex (sock, GNUNET_ECRS_DBLOCK_SIZE, &fileId))
+ {
+ GNUNET_GE_BREAK (ectx, 0);
+ goto FAILURE;
+ }
+ }
+ else
+ {
+ GNUNET_GE_BREAK (ectx, 0);
+ goto FAILURE;
+ }
+ }
+ GNUNET_free (iblocks[treedepth]);
+ /* free resources */
+ GNUNET_free (iblocks);
+ GNUNET_free (dblock);
+ CLOSE (fd);
+ GNUNET_client_connection_destroy (sock);
+ return GNUNET_OK;
+FAILURE:
+ for (i = 0; i <= treedepth; i++)
+ GNUNET_free_non_null (iblocks[i]);
+ GNUNET_free (iblocks);
+ GNUNET_free (dblock);
+ CLOSE (fd);
+ GNUNET_client_connection_destroy (sock);
+ return GNUNET_SYSERR;
+}
+
+/* end of unindex.c */