/**
* @file fs/fs_unindex.c
- * @author Krista Bennett
+ * @author Krista Grothoff
* @author Christian Grothoff
* @brief Unindex file.
- *
- * TODO:
- * - code cleanup (share more with upload.c)
*/
-
#include "platform.h"
#include "gnunet_constants.h"
#include "gnunet_fs_service.h"
#include "gnunet_protocols.h"
#include "fs.h"
+#include "fs_tree.h"
/**
- * Context for "GNUNET_FS_get_indexed_files".
- */
-struct GetIndexedContext
-{
- /**
- * Handle to global FS context.
- */
- struct GNUNET_FS_Handle *h;
-
- /**
- * Connection to the FS service.
- */
- struct GNUNET_CLIENT_Connection *client;
-
- /**
- * Function to call for each indexed file.
- */
- GNUNET_FS_IndexedFileProcessor iterator;
-
- /**
- * Closure for iterator.
- */
- void *iterator_cls;
-
- /**
- * Continuation to trigger at the end.
- */
- GNUNET_SCHEDULER_Task cont;
-
- /**
- * Closure for cont.
- */
- void *cont_cls;
-};
-
-
-/**
- * Function called on each response from the FS
- * service with information about indexed files.
+ * Function called by the tree encoder to obtain
+ * a block of plaintext data (for the lowest level
+ * of the tree).
*
- * @param cls closure (of type "struct GetIndexedContext*")
- * @param msg message with indexing information
+ * @param cls our publishing context
+ * @param offset identifies which block to get
+ * @param max (maximum) number of bytes to get; returning
+ * fewer will also cause errors
+ * @param buf where to copy the plaintext buffer
+ * @param emsg location to store an error message (on error)
+ * @return number of bytes copied to buf, 0 on error
*/
-static void
-handle_index_info (void *cls,
- const struct GNUNET_MessageHeader *msg)
+static size_t
+unindex_reader (void *cls,
+ uint64_t offset,
+ size_t max,
+ void *buf,
+ char **emsg)
{
- struct GetIndexedContext *gic = cls;
- const struct IndexInfoMessage *iim;
- uint16_t msize;
- const char *filename;
+ struct GNUNET_FS_UnindexContext *uc = cls;
+ size_t pt_size;
- if (NULL == msg)
+ pt_size = GNUNET_MIN(max,
+ uc->file_size - offset);
+ if (offset !=
+ GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Failed to receive response for `%s' request from `%s' service.\n"),
- "GET_INDEXED",
- "fs");
- GNUNET_SCHEDULER_add_continuation (gic->h->sched,
- GNUNET_NO,
- gic->cont,
- gic->cont_cls,
- GNUNET_SCHEDULER_REASON_TIMEOUT);
- GNUNET_CLIENT_disconnect (gic->client);
- GNUNET_free (gic);
- return;
- }
- if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END)
- {
- /* normal end-of-list */
- GNUNET_SCHEDULER_add_continuation (gic->h->sched,
- GNUNET_NO,
- gic->cont,
- gic->cont_cls,
- GNUNET_SCHEDULER_REASON_PREREQ_DONE);
- GNUNET_CLIENT_disconnect (gic->client);
- GNUNET_free (gic);
- return;
+ *emsg = GNUNET_strdup (_("Failed to find given position in file"));
+ return 0;
}
- msize = ntohs (msg->size);
- iim = (const struct IndexInfoMessage*) msg;
- filename = (const char*) &iim[1];
- if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY) ||
- (msize <= sizeof (struct IndexInfoMessage)) ||
- (filename[msize-sizeof (struct IndexInfoMessage) -1] != '\0') )
+ if (pt_size !=
+ GNUNET_DISK_file_read (uc->fh,
+ buf,
+ pt_size))
{
- /* bogus reply */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Failed to receive valid response for `%s' request from `%s' service.\n"),
- "GET_INDEXED",
- "fs");
- GNUNET_SCHEDULER_add_continuation (gic->h->sched,
- GNUNET_NO,
- gic->cont,
- gic->cont_cls,
- GNUNET_SCHEDULER_REASON_TIMEOUT);
- GNUNET_CLIENT_disconnect (gic->client);
- GNUNET_free (gic);
- return;
- }
- if (GNUNET_OK !=
- gic->iterator (gic->iterator_cls,
- filename,
- &iim->file_id))
- {
- GNUNET_SCHEDULER_add_continuation (gic->h->sched,
- GNUNET_NO,
- gic->cont,
- gic->cont_cls,
- GNUNET_SCHEDULER_REASON_PREREQ_DONE);
- GNUNET_CLIENT_disconnect (gic->client);
- GNUNET_free (gic);
- return;
+ *emsg = GNUNET_strdup (_("Failed to read file"));
+ return 0;
}
- /* get more */
- GNUNET_CLIENT_receive (gic->client,
- &handle_index_info,
- gic,
- GNUNET_CONSTANTS_SERVICE_TIMEOUT);
+ return pt_size;
}
/**
- * Transmit the request to get a list of all
- * indexed files to the "FS" service.
+ * Fill in all of the generic fields for
+ * an unindex event.
*
- * @param cls closure (of type "struct GetIndexedContext*")
- * @param size number of bytes availabe in buf
- * @param buf where to write the message, NULL on error
- * @return number of bytes written to buf
+ * @param pi structure to fill in
+ * @param uc overall unindex context
+ * @param offset where we are in the file (for progress)
*/
-static size_t
-transmit_get_indexed (void *cls,
- size_t size,
- void *buf)
+static void
+make_unindex_status (struct GNUNET_FS_ProgressInfo *pi,
+ struct GNUNET_FS_UnindexContext *uc,
+ uint64_t offset)
{
- struct GetIndexedContext *gic = cls;
- struct GNUNET_MessageHeader *hdr;
-
- if (NULL == buf)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Failed to transmit `%s' request to `%s' service.\n"),
- "GET_INDEXED",
- "fs");
- GNUNET_SCHEDULER_add_continuation (gic->h->sched,
- GNUNET_NO,
- gic->cont,
- gic->cont_cls,
- GNUNET_SCHEDULER_REASON_TIMEOUT);
- GNUNET_CLIENT_disconnect (gic->client);
- GNUNET_free (gic);
- return 0;
- }
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
- hdr = buf;
- hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
- hdr->type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET);
- GNUNET_CLIENT_receive (gic->client,
- &handle_index_info,
- gic,
- GNUNET_CONSTANTS_SERVICE_TIMEOUT);
- return sizeof (struct GNUNET_MessageHeader);
+ pi->value.unindex.uc = uc;
+ pi->value.unindex.cctx = uc->client_info;
+ pi->value.unindex.filename = uc->filename;
+ pi->value.unindex.size = uc->file_size;
+ pi->value.unindex.eta
+ = GNUNET_TIME_calculate_eta (uc->start_time,
+ offset,
+ uc->file_size);
+ pi->value.unindex.duration = GNUNET_TIME_absolute_get_duration (uc->start_time);
+ pi->value.unindex.completed = offset;
}
/**
- * Iterate over all indexed files.
+ * Function called with information about our
+ * progress in computing the tree encoding.
*
- * @param h handle to the file sharing subsystem
- * @param iterator function to call on each indexed file
- * @param iterator_cls closure for iterator
- * @param cont continuation to call when done;
- * reason should be "TIMEOUT" (on
- * error) or "PREREQ_DONE" (on success)
- * @param cont_cls closure for cont
+ * @param cls closure
+ * @param offset where are we in the file
+ * @param pt_block plaintext of the currently processed block
+ * @param pt_size size of pt_block
+ * @param depth depth of the block in the tree
*/
-void
-GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h,
- GNUNET_FS_IndexedFileProcessor iterator,
- void *iterator_cls,
- GNUNET_SCHEDULER_Task cont,
- void *cont_cls)
+static void
+unindex_progress (void *cls,
+ uint64_t offset,
+ const void *pt_block,
+ size_t pt_size,
+ unsigned int depth)
{
- struct GNUNET_CLIENT_Connection *client;
- struct GetIndexedContext *gic;
-
- client = GNUNET_CLIENT_connect (h->sched,
- "fs",
- h->cfg);
- if (NULL == client)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Failed to not connect to `%s' service.\n"),
- "fs");
- GNUNET_SCHEDULER_add_continuation (h->sched,
- GNUNET_NO,
- cont,
- cont_cls,
- GNUNET_SCHEDULER_REASON_TIMEOUT);
- return;
- }
-
- gic = GNUNET_malloc (sizeof (struct GetIndexedContext));
- gic->h = h;
- gic->client = client;
- gic->iterator = iterator;
- gic->iterator_cls = iterator_cls;
- gic->cont = cont;
- gic->cont_cls = cont_cls;
- GNUNET_CLIENT_notify_transmit_ready (client,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_CONSTANTS_SERVICE_TIMEOUT,
- &transmit_get_indexed,
- gic);
+ struct GNUNET_FS_UnindexContext *uc = cls;
+ struct GNUNET_FS_ProgressInfo pi;
+
+ pi.status = GNUNET_FS_STATUS_UNINDEX_PROGRESS;
+ make_unindex_status (&pi, uc, offset);
+ pi.value.unindex.specifics.progress.data = pt_block;
+ pi.value.unindex.specifics.progress.offset = offset;
+ pi.value.unindex.specifics.progress.data_len = pt_size;
+ pi.value.unindex.specifics.progress.depth = depth;
+ uc->client_info
+ = uc->h->upcb (uc->h->upcb_cls,
+ &pi);
}
-
+
/**
- * Unindex a file.
+ * We've encountered an error during
+ * unindexing. Signal the client.
*
- * @param h handle to the file sharing subsystem
- * @param filename file to unindex
- * @return NULL on error, otherwise handle
+ * @param uc context for the failed unindexing operation
+ * @param emsg the error message
*/
-struct GNUNET_FS_UnindexContext *
-GNUNET_FS_unindex (struct GNUNET_FS_Handle *h,
- const char *filename)
+static void
+signal_unindex_error (struct GNUNET_FS_UnindexContext *uc,
+ const char *emsg)
{
- // 1: compute file-id (hash over entire file)
- // 2: notify FS service about file no longer being indexed
- // 3: remove corresponding blocks from datastore!
- return NULL;
+ struct GNUNET_FS_ProgressInfo pi;
+
+ pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR;
+ make_unindex_status (&pi, uc, 0);
+ pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
+ pi.value.unindex.specifics.error.message = emsg;
+ uc->client_info
+ = uc->h->upcb (uc->h->upcb_cls,
+ &pi);
}
/**
- * Clean up after completion of an unindex operation.
+ * Continuation called to notify client about result of the
+ * datastore removal operation.
*
- * @param uc handle
+ * @param cls closure
+ * @param success GNUNET_SYSERR on failure
+ * @param msg NULL on success, otherwise an error message
*/
-void
-GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
+static void
+process_cont (void *cls,
+ int success,
+ const char *msg)
{
+ struct GNUNET_FS_UnindexContext *uc = cls;
+ if (success == GNUNET_SYSERR)
+ {
+ signal_unindex_error (uc,
+ msg);
+ return;
+ }
+
+ GNUNET_FS_tree_encoder_next (uc->tc);
}
-
-#if 0
-
-#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.
+ * Function called asking for the current (encoded)
+ * block to be processed. After processing the
+ * client should either call "GNUNET_FS_tree_encode_next"
+ * or (on error) "GNUNET_FS_tree_encode_finish".
*
- * 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!).
+ * @param cls closure
+ * @param query the query for the block (key for lookup in the datastore)
+ * @param offset offset of the block
+ * @param type type of the block (IBLOCK or DBLOCK)
+ * @param block the (encrypted) block
+ * @param block_size size of block (in bytes)
*/
-static int
-pushBlock (struct GNUNET_ClientServerConnection *sock,
- const GNUNET_EC_ContentHashKey * chk, unsigned int level,
- GNUNET_DatastoreValue ** iblocks)
+static void
+unindex_process (void *cls,
+ const GNUNET_HashCode *query,
+ uint64_t offset,
+ uint32_t type,
+ const void *block,
+ uint16_t block_size)
{
- 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)
+ struct GNUNET_FS_UnindexContext *uc = cls;
+ uint32_t size;
+ const void *data;
+ struct OnDemandBlock odb;
+
+ if (type != GNUNET_DATASTORE_BLOCKTYPE_DBLOCK)
{
- 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);
+ size = block_size;
+ data = block;
}
- /* 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;
+ else /* on-demand encoded DBLOCK */
+ {
+ size = sizeof(struct OnDemandBlock);
+ odb.offset = GNUNET_htonll (offset);
+ odb.file_id = uc->file_id;
+ data = &odb;
+ }
+ GNUNET_DATASTORE_remove (uc->dsh,
+ query,
+ size,
+ data,
+ &process_cont,
+ uc,
+ GNUNET_CONSTANTS_SERVICE_TIMEOUT);
}
-
/**
- * Undo sym-linking operation:
- * a) check if we have a symlink
- * b) delete symbolic link
+ * Function called when the tree encoder has
+ * processed all blocks. Clean up.
+ *
+ * @param cls our unindexing context
+ * @param tc not used
*/
-static int
-undoSymlinking (struct GNUNET_GE_Context *ectx,
- const char *fn,
- const GNUNET_HashCode * fileId,
- struct GNUNET_ClientServerConnection *sock)
+static void
+unindex_finish (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- 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))
+ struct GNUNET_FS_UnindexContext *uc = cls;
+ char *emsg;
+ struct GNUNET_FS_Uri *uri;
+ struct GNUNET_FS_ProgressInfo pi;
+
+ GNUNET_FS_tree_encoder_finish (uc->tc,
+ &uri,
+ &emsg);
+ if (uri != NULL)
+ GNUNET_FS_uri_destroy (uri);
+ GNUNET_DISK_file_close (uc->fh);
+ uc->fh = NULL;
+ GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
+ uc->dsh = NULL;
+ if (emsg != NULL)
{
- GNUNET_GE_LOG_STRERROR_FILE (ectx,
- GNUNET_GE_ERROR | GNUNET_GE_BULK |
- GNUNET_GE_USER | GNUNET_GE_ADMIN, "stat",
- fn);
- return GNUNET_SYSERR;
+ signal_unindex_error (uc, emsg);
+ GNUNET_free (emsg);
}
-#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;
+ else
+ {
+ pi.status = GNUNET_FS_STATUS_UNINDEX_COMPLETED;
+ make_unindex_status (&pi, uc, uc->file_size);
+ pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
+ uc->client_info
+ = uc->h->upcb (uc->h->upcb_cls,
+ &pi);
}
- GNUNET_free (serverFN);
- return GNUNET_OK;
}
-
/**
- * Unindex a file.
+ * Function called with the response from the
+ * FS service to our unindexing request.
*
- * @return GNUNET_SYSERR if the unindexing failed (i.e. not indexed)
+ * @param cls closure, unindex context
+ * @param msg NULL on timeout, otherwise the response
*/
-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)
+static void
+process_fs_response (void *cls,
+ const struct GNUNET_MessageHeader *msg)
{
- 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))
+ struct GNUNET_FS_UnindexContext *uc = cls;
+
+ GNUNET_CLIENT_disconnect (uc->client, GNUNET_NO);
+ uc->client = NULL;
+ if (uc->state != UNINDEX_STATE_FS_NOTIFY)
{
- GNUNET_GE_BREAK (ectx, 0);
- return GNUNET_SYSERR;
+ GNUNET_FS_unindex_stop (uc);
+ return;
}
- 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))
+ if (NULL == msg)
{
- GNUNET_client_connection_destroy (sock);
- GNUNET_GE_BREAK (ectx, 0);
- return GNUNET_SYSERR;
+ uc->state = UNINDEX_STATE_ERROR;
+ signal_unindex_error (uc,
+ _("Timeout waiting for `fs' service."));
+ return;
}
- 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)
+ if (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK)
{
- GNUNET_client_connection_destroy (sock);
- return GNUNET_SYSERR;
+ uc->state = UNINDEX_STATE_ERROR;
+ signal_unindex_error (uc,
+ _("Invalid response from `fs' service."));
+ return;
}
- 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++)
+ uc->state = UNINDEX_STATE_DS_REMOVE;
+ uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg,
+ uc->h->sched);
+ if (NULL == uc->dsh)
{
- 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);
+ uc->state = UNINDEX_STATE_ERROR;
+ signal_unindex_error (uc,
+ _("Failed to connect to `datastore' service."));
+ return;
+ }
+ uc->fh = GNUNET_DISK_file_open (uc->filename,
+ GNUNET_DISK_OPEN_READ,
+ GNUNET_DISK_PERM_NONE);
+ if (NULL == uc->fh)
+ {
+ GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
+ uc->dsh = NULL;
+ uc->state = UNINDEX_STATE_ERROR;
+ signal_unindex_error (uc,
+ _("Failed to open file for unindexing."));
+ return;
}
+ uc->tc = GNUNET_FS_tree_encoder_create (uc->h,
+ uc->file_size,
+ uc,
+ &unindex_reader,
+ &unindex_process,
+ &unindex_progress,
+ &unindex_finish);
+ GNUNET_FS_tree_encoder_next (uc->tc);
+}
+
- pos = 0;
- while (pos < filesize)
+/**
+ * Function called once the hash of the file
+ * that is being unindexed has been computed.
+ *
+ * @param cls closure, unindex context
+ * @param file_id computed hash, NULL on error
+ */
+static void
+process_hash (void *cls,
+ const GNUNET_HashCode *file_id)
+{
+ struct GNUNET_FS_UnindexContext *uc = cls;
+ struct UnindexMessage req;
+
+ if (uc->state != UNINDEX_STATE_HASHING)
{
- 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);
+ GNUNET_FS_unindex_stop (uc);
+ return;
}
- if (tt != NULL)
- if (GNUNET_OK != tt (ttClosure))
- goto FAILURE;
- for (i = 0; i < treedepth; i++)
+ if (file_id == NULL)
{
- 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;
+ uc->state = UNINDEX_STATE_ERROR;
+ signal_unindex_error (uc,
+ _("Failed to compute hash of file."));
+ return;
}
+ uc->file_id = *file_id;
+ uc->state = UNINDEX_STATE_FS_NOTIFY;
+ uc->client = GNUNET_CLIENT_connect (uc->h->sched,
+ "fs",
+ uc->h->cfg);
+ req.header.size = htons (sizeof (struct UnindexMessage));
+ req.header.type = htons (GNUNET_MESSAGE_TYPE_FS_UNINDEX);
+ req.reserved = 0;
+ req.file_id = *file_id;
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CLIENT_transmit_and_get_response (uc->client,
+ &req.header,
+ GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_YES,
+ &process_fs_response,
+ uc));
+}
+
+
+/**
+ * Unindex a file.
+ *
+ * @param h handle to the file sharing subsystem
+ * @param filename file to unindex
+ * @param cctx initial value for the client context
+ * @return NULL on error, otherwise handle
+ */
+struct GNUNET_FS_UnindexContext *
+GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
+ const char *filename,
+ void *cctx)
+{
+ struct GNUNET_FS_UnindexContext *ret;
+ struct GNUNET_FS_ProgressInfo pi;
+ uint64_t size;
+
+ if (GNUNET_OK !=
+ GNUNET_DISK_file_size (filename,
+ &size,
+ GNUNET_YES))
+ return NULL;
+ ret = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext));
+ ret->h = h;
+ ret->filename = GNUNET_strdup (filename);
+ ret->start_time = GNUNET_TIME_absolute_get ();
+ ret->file_size = size;
+ ret->client_info = cctx;
+
+ // FIXME: make persistent!
+ pi.status = GNUNET_FS_STATUS_UNINDEX_START;
+ make_unindex_status (&pi, ret, 0);
+ pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
+ ret->client_info
+ = h->upcb (h->upcb_cls,
+ &pi);
+ GNUNET_CRYPTO_hash_file (h->sched,
+ GNUNET_SCHEDULER_PRIORITY_IDLE,
+ filename,
+ HASHING_BLOCKSIZE,
+ &process_hash,
+ ret);
+ return ret;
+}
- if (wasIndexed)
+
+/**
+ * Clean up after completion of an unindex operation.
+ *
+ * @param uc handle
+ */
+void
+GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
+{
+ struct GNUNET_FS_ProgressInfo pi;
+
+ if ( (uc->state != UNINDEX_STATE_COMPLETE) &&
+ (uc->state != UNINDEX_STATE_ERROR) )
{
- 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;
- }
+ uc->state = UNINDEX_STATE_ABORTED;
+ return;
}
- 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;
+ // FIXME: make unpersistent!
+ make_unindex_status (&pi, uc,
+ (uc->state == UNINDEX_STATE_COMPLETE)
+ ? uc->file_size : 0);
+ pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED;
+ pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO;
+ uc->client_info
+ = uc->h->upcb (uc->h->upcb_cls,
+ &pi);
+ GNUNET_break (NULL == uc->client_info);
+ GNUNET_free (uc->filename);
+ GNUNET_free (uc);
}
-#endif
-
/* end of fs_unindex.c */