gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r8841 - in gnunet: . src/fs src/include


From: gnunet
Subject: [GNUnet-SVN] r8841 - in gnunet: . src/fs src/include
Date: Sat, 22 Aug 2009 11:57:31 -0600

Author: grothoff
Date: 2009-08-22 11:57:31 -0600 (Sat, 22 Aug 2009)
New Revision: 8841

Added:
   gnunet/src/fs/fs.c
   gnunet/src/fs/fs_download.c
   gnunet/src/fs/fs_file_information.c
   gnunet/src/fs/fs_namespace.c
   gnunet/src/fs/fs_publish.c
   gnunet/src/fs/fs_search.c
   gnunet/src/fs/fs_test.c
   gnunet/src/fs/fs_unindex.c
   gnunet/src/fs/test_fs_collection_data.conf
   gnunet/src/fs/test_fs_download.c
   gnunet/src/fs/test_fs_download_recursive.c
   gnunet/src/fs/test_fs_search_persistence.c
   gnunet/src/fs/test_fs_search_ranking.c
   gnunet/src/fs/test_fs_start_stop.c
   gnunet/src/fs/test_namespace.c
Modified:
   gnunet/TODO
   gnunet/src/fs/Makefile.am
   gnunet/src/fs/fs.h
   gnunet/src/fs/fs_directory.c
   gnunet/src/fs/fs_uri.c
   gnunet/src/fs/test_fs_collection.c
   gnunet/src/fs/test_fs_directory.c
   gnunet/src/fs/test_fs_getopt.c
   gnunet/src/fs/test_fs_uri.c
   gnunet/src/include/gnunet_fs_service.h
Log:
stuff

Modified: gnunet/TODO
===================================================================
--- gnunet/TODO 2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/TODO 2009-08-22 17:57:31 UTC (rev 8841)
@@ -39,8 +39,8 @@
   - review FS API [Nils, Amatus, CG]
   - design network structs (CS)
   - implement FS library
-    + URI API
-    + getopt API
+    + URI API -- DONE (but do more testing)
+    + getopt API -- DONE (but do more testing)
     + persistence mechanism
     + sharing API
       ~ file-information

Modified: gnunet/src/fs/Makefile.am
===================================================================
--- gnunet/src/fs/Makefile.am   2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/Makefile.am   2009-08-22 17:57:31 UTC (rev 8841)
@@ -13,9 +13,13 @@
 lib_LTLIBRARIES = libgnunetfs.la
 
 libgnunetfs_la_SOURCES = \
+  fs.c \
   fs_collection.c \
   fs_directory.c \
+  fs_file_information.c \
   fs_getopt.c \
+  fs_publish.c \
+  fs_namespace.c \
   fs_uri.c 
 
 libgnunetfs_la_LIBADD = \
@@ -31,8 +35,8 @@
 # gnunet-directory 
 # gnunet-download 
 # gnunet-pseudonym 
+# gnunet-publish 
 # gnunet-search
-# gnunet-share 
 # gnunet-unindex 
 
 #gnunet_directory_SOURCES = 
@@ -76,4 +80,5 @@
   $(top_builddir)/src/util/libgnunetutil.la  
 
 EXTRA_DIST = \
+  test_fs_collection_data.conf \
   test_fs_uri_data.conf

Added: gnunet/src/fs/fs.c
===================================================================
--- gnunet/src/fs/fs.c                          (rev 0)
+++ gnunet/src/fs/fs.c  2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,65 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 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 fs/fs.c
+ * @brief main FS functions
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_fs_service.h"
+#include "fs.h"
+
+
+
+/**
+ * Setup a connection to the file-sharing service.
+ *
+ * @param sched scheduler to use
+ * @param cfg configuration to use
+ * @param client_name unique identifier for this client 
+ * @param upcb function to call to notify about FS actions
+ * @param upcb_cls closure for upcb
+ */
+struct GNUNET_FS_Handle *
+GNUNET_FS_start (struct GNUNET_SCHEDULER_Handle *sched,
+                const struct GNUNET_CONFIGURATION_Handle *cfg,
+                const char *client_name,
+                GNUNET_FS_ProgressCallback upcb,
+                void *upcb_cls)
+{
+  return NULL;
+}
+
+
+/**
+ * Close our connection with the file-sharing service.
+ * The callback given to GNUNET_FS_start will no longer be
+ * called after this function returns.
+ *
+ * @param h handle that was returned from GNUNET_FS_start
+ */                    
+void 
+GNUNET_FS_stop (struct GNUNET_FS_Handle *h)
+{
+}
+
+/* end of fs.c */

Modified: gnunet/src/fs/fs.h
===================================================================
--- gnunet/src/fs/fs.h  2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/fs.h  2009-08-22 17:57:31 UTC (rev 8841)
@@ -129,4 +129,16 @@
 
 };
 
+
+/**
+ * Information for a file or directory that is
+ * about to be published.
+ */
+struct GNUNET_FS_FileInformation 
+{
+
+
+};
+
+
 #endif

Modified: gnunet/src/fs/fs_directory.c
===================================================================
--- gnunet/src/fs/fs_directory.c        2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/fs_directory.c        2009-08-22 17:57:31 UTC (rev 8841)
@@ -231,6 +231,13 @@
     }
 }
 
+
+void
+GNUNET_FS_directory_create ()
+{
+}
+
+
 #if 0
 
 

Added: gnunet/src/fs/fs_download.c
===================================================================
--- gnunet/src/fs/fs_download.c                         (rev 0)
+++ gnunet/src/fs/fs_download.c 2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,923 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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/download.c
+ * @brief DOWNLOAD helper methods (which do the real work).
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_ecrs_lib.h"
+#include "gnunet_fs_lib.h"
+#include "gnunet_identity_lib.h"
+#include "ecrs_core.h"
+#include "ecrs.h"
+#include "fs.h"
+#include "tree.h"
+
+#define DEBUG_DOWNLOAD GNUNET_NO
+
+/**
+ * Node-specific data (not shared, keep small!). 152 bytes.
+ * Nodes are kept in a doubly-linked list.
+ */
+struct Node
+{
+  /**
+   * Pointer to shared data between all nodes (request manager,
+   * progress data, etc.).
+   */
+  struct GNUNET_ECRS_DownloadContext *ctx;
+
+  /**
+   * Previous entry in DLL.
+   */
+  struct Node *prev;
+
+  /**
+   * Next entry in DLL.
+   */
+  struct Node *next;
+
+  /**
+   * What is the GNUNET_EC_ContentHashKey for this block?
+   */
+  GNUNET_EC_ContentHashKey chk;
+
+  /**
+   * At what offset (on the respective level!) is this
+   * block?
+   */
+  unsigned long long offset;
+
+  /**
+   * 0 for dblocks, >0 for iblocks.
+   */
+  unsigned int level;
+
+};
+
+/**
+ * @brief structure that keeps track of currently pending requests for
+ *        a download
+ *
+ * Handle to the state of a request manager.  Here we keep track of
+ * which queries went out with which priorities and which nodes in
+ * the merkle-tree are waiting for the replies.
+ */
+struct GNUNET_ECRS_DownloadContext
+{
+
+  /**
+   * Total number of bytes in the file.
+   */
+  unsigned long long total;
+
+  /**
+   * Number of bytes already obtained
+   */
+  unsigned long long completed;
+
+  /**
+   * Starting-offset in file (for partial download)
+   */
+  unsigned long long offset;
+
+  /**
+   * Length of the download (starting at offset).
+   */
+  unsigned long long length;
+
+  /**
+   * Time download was started.
+   */
+  GNUNET_CronTime startTime;
+
+  /**
+   * Doubly linked list of all pending requests (head)
+   */
+  struct Node *head;
+
+  /**
+   * Doubly linked list of all pending requests (tail)
+   */
+  struct Node *tail;
+
+  /**
+   * FSLIB context for issuing requests.
+   */
+  struct GNUNET_FS_SearchContext *sctx;
+
+  /**
+   * Context for error reporting.
+   */
+  struct GNUNET_GE_Context *ectx;
+
+  /**
+   * Configuration information.
+   */
+  struct GNUNET_GC_Configuration *cfg;
+
+  /**
+   * The file handle.
+   */
+  int handle;
+
+  /**
+   * Do we exclusively own this sctx?
+   */
+  int my_sctx;
+
+  /**
+   * The base-filename
+   */
+  char *filename;
+
+  /**
+   * Main thread running the operation.
+   */
+  struct GNUNET_ThreadHandle *main;
+
+  /**
+   * Function to call when we make progress.
+   */
+  GNUNET_ECRS_DownloadProgressCallback dpcb;
+
+  /**
+   * Extra argument to dpcb.
+   */
+  void *dpcbClosure;
+
+  /**
+   * Identity of the peer having the content, or all-zeros
+   * if we don't know of such a peer.
+   */
+  GNUNET_PeerIdentity target;
+
+  /**
+   * Abort?  Flag that can be set at any time
+   * to abort the RM as soon as possible.  Set
+   * to GNUNET_YES during orderly shutdown,
+   * set to GNUNET_SYSERR on error.
+   */
+  int abortFlag;
+
+  /**
+   * Do we have a specific peer from which we download
+   * from?
+   */
+  int have_target;
+
+  /**
+   * Desired anonymity level for the download.
+   */
+  unsigned int anonymityLevel;
+
+  /**
+   * The depth of the file-tree.
+   */
+  unsigned int treedepth;
+
+};
+
+static int
+content_receive_callback (const GNUNET_HashCode * query,
+                          const GNUNET_DatastoreValue * reply, void *cls,
+                          unsigned long long uid);
+
+
+/**
+ * Close the files and free the associated resources.
+ *
+ * @param self reference to the download context
+ */
+static void
+free_request_manager (struct GNUNET_ECRS_DownloadContext *rm)
+{
+  struct Node *pos;
+
+  if (rm->abortFlag == GNUNET_NO)
+    rm->abortFlag = GNUNET_YES;
+  if (rm->my_sctx == GNUNET_YES)
+    GNUNET_FS_destroy_search_context (rm->sctx);
+  else
+    GNUNET_FS_suspend_search_context (rm->sctx);
+  while (rm->head != NULL)
+    {
+      pos = rm->head;
+      GNUNET_DLL_remove (rm->head, rm->tail, pos);
+      if (rm->my_sctx != GNUNET_YES)
+        GNUNET_FS_stop_search (rm->sctx, &content_receive_callback, pos);
+      GNUNET_free (pos);
+    }
+  if (rm->my_sctx != GNUNET_YES)
+    GNUNET_FS_resume_search_context (rm->sctx);
+  GNUNET_GE_ASSERT (NULL, rm->tail == NULL);
+  if (rm->handle >= 0)
+    CLOSE (rm->handle);
+  if (rm->main != NULL)
+    GNUNET_thread_release_self (rm->main);
+  GNUNET_free_non_null (rm->filename);
+  rm->sctx = NULL;
+  GNUNET_free (rm);
+}
+
+/**
+ * Read method.
+ *
+ * @param self reference to the download context
+ * @param level level in the tree to read/write at
+ * @param pos position where to read or write
+ * @param buf where to read from or write to
+ * @param len how many bytes to read or write
+ * @return number of bytes read, GNUNET_SYSERR on error
+ */
+static int
+read_from_files (struct GNUNET_ECRS_DownloadContext *self,
+                 unsigned int level,
+                 unsigned long long pos, void *buf, unsigned int len)
+{
+  if ((level > 0) || (self->handle == -1))
+    return GNUNET_SYSERR;
+  LSEEK (self->handle, pos, SEEK_SET);
+  return READ (self->handle, buf, len);
+}
+
+/**
+ * Write method.
+ *
+ * @param self reference to the download context
+ * @param level level in the tree to write to
+ * @param pos position where to  write
+ * @param buf where to write to
+ * @param len how many bytes to write
+ * @return number of bytes written, GNUNET_SYSERR on error
+ */
+static int
+write_to_files (struct GNUNET_ECRS_DownloadContext *self,
+                unsigned int level,
+                unsigned long long pos, void *buf, unsigned int len)
+{
+  int ret;
+
+  if (level > 0)
+    return len;                 /* lie -- no more temps */
+  if (self->handle == -1)
+    return len;
+  LSEEK (self->handle, pos, SEEK_SET);
+  ret = WRITE (self->handle, buf, len);
+  if (ret != len)
+    GNUNET_GE_LOG_STRERROR_FILE (self->ectx,
+                                 GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                                 GNUNET_GE_USER, "write", self->filename);
+  return ret;
+}
+
+/**
+ * Queue a request for execution.
+ *
+ * @param rm the request manager struct from createRequestManager
+ * @param node the node to call once a reply is received
+ */
+static void
+add_request (struct Node *node)
+{
+  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;
+
+  GNUNET_DLL_insert (rm->head, rm->tail, node);
+  GNUNET_FS_start_search (rm->sctx,
+                          rm->have_target == GNUNET_NO ? NULL : &rm->target,
+                          GNUNET_ECRS_BLOCKTYPE_DATA, 1,
+                          &node->chk.query,
+                          rm->anonymityLevel,
+                          &content_receive_callback, node);
+}
+
+static void
+signal_abort (struct GNUNET_ECRS_DownloadContext *rm, const char *msg)
+{
+  rm->abortFlag = GNUNET_SYSERR;
+  if ((rm->head != NULL) && (rm->dpcb != NULL))
+    rm->dpcb (rm->length + 1, 0, 0, 0, msg, 0, rm->dpcbClosure);
+  GNUNET_thread_stop_sleep (rm->main);
+}
+
+/**
+ * Dequeue a request.
+ *
+ * @param self the request manager struct from createRequestManager
+ * @param node the block for which the request is canceled
+ */
+static void
+delete_node (struct Node *node)
+{
+  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;
+
+  GNUNET_DLL_remove (rm->head, rm->tail, node);
+  GNUNET_free (node);
+  if (rm->head == NULL)
+    GNUNET_thread_stop_sleep (rm->main);
+}
+
+/**
+ * Compute how many bytes of data are stored in
+ * this node.
+ */
+static unsigned int
+get_node_size (const struct Node *node)
+{
+  unsigned int i;
+  unsigned int ret;
+  unsigned long long rsize;
+  unsigned long long spos;
+  unsigned long long epos;
+
+  GNUNET_GE_ASSERT (node->ctx->ectx, node->offset < node->ctx->total);
+  if (node->level == 0)
+    {
+      ret = GNUNET_ECRS_DBLOCK_SIZE;
+      if (node->offset + (unsigned long long) ret > node->ctx->total)
+        ret = (unsigned int) (node->ctx->total - node->offset);
+#if DEBUG_DOWNLOAD
+      GNUNET_GE_LOG (node->ctx->rm->ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                     "Node at offset %llu and level %d has size %u\n",
+                     node->offset, node->level, ret);
+#endif
+      return ret;
+    }
+  rsize = GNUNET_ECRS_DBLOCK_SIZE;
+  for (i = 0; i < node->level - 1; i++)
+    rsize *= GNUNET_ECRS_CHK_PER_INODE;
+  spos = rsize * (node->offset / sizeof (GNUNET_EC_ContentHashKey));
+  epos = spos + rsize * GNUNET_ECRS_CHK_PER_INODE;
+  if (epos > node->ctx->total)
+    epos = node->ctx->total;
+  ret = (epos - spos) / rsize;
+  if (ret * rsize < epos - spos)
+    ret++;                      /* need to round up! */
+#if DEBUG_DOWNLOAD
+  GNUNET_GE_LOG (node->ctx->rm->ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "Node at offset %llu and level %d has size %u\n",
+                 node->offset, node->level,
+                 ret * sizeof (GNUNET_EC_ContentHashKey));
+#endif
+  return ret * sizeof (GNUNET_EC_ContentHashKey);
+}
+
+/**
+ * Notify client about progress.
+ */
+static void
+notify_client_about_progress (const struct Node *node,
+                              const char *data, unsigned int size)
+{
+  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;
+  GNUNET_CronTime eta;
+
+  if ((rm->abortFlag != GNUNET_NO) || (node->level != 0))
+    return;
+  rm->completed += size;
+  eta = GNUNET_get_time ();
+  if (rm->completed > 0)
+    eta = (GNUNET_CronTime) (rm->startTime +
+                             (((double) (eta - rm->startTime) /
+                               (double) rm->completed)) *
+                             (double) rm->length);
+  if (rm->dpcb != NULL)
+    rm->dpcb (rm->length,
+              rm->completed, eta, node->offset, data, size, rm->dpcbClosure);
+}
+
+
+/**
+ * DOWNLOAD children of this GNUNET_EC_IBlock.
+ *
+ * @param node the node for which the children should be downloaded
+ * @param data data for the node
+ * @param size size of data
+ */
+static void iblock_download_children (const struct Node *node,
+                                      const char *data, unsigned int size);
+
+/**
+ * Check if self block is already present on the drive.  If the block
+ * is a dblock and present, the ProgressModel is notified. If the
+ * block is present and it is an iblock, downloading the children is
+ * triggered.
+ *
+ * Also checks if the block is within the range of blocks
+ * that we are supposed to download.  If not, the method
+ * returns as if the block is present but does NOT signal
+ * progress.
+ *
+ * @param node that is checked for presence
+ * @return GNUNET_YES if present, GNUNET_NO if not.
+ */
+static int
+check_node_present (const struct Node *node)
+{
+  int res;
+  int ret;
+  char *data;
+  unsigned int size;
+  GNUNET_HashCode hc;
+
+  size = get_node_size (node);
+  /* first check if node is within range.
+     For now, keeping it simple, we only do
+     this for level-0 nodes */
+  if ((node->level == 0) &&
+      ((node->offset + size < node->ctx->offset) ||
+       (node->offset >= node->ctx->offset + node->ctx->length)))
+    return GNUNET_YES;
+  data = GNUNET_malloc (size);
+  ret = GNUNET_NO;
+  res = read_from_files (node->ctx, node->level, node->offset, data, size);
+  if (res == size)
+    {
+      GNUNET_hash (data, size, &hc);
+      if (0 == memcmp (&hc, &node->chk.key, sizeof (GNUNET_HashCode)))
+        {
+          notify_client_about_progress (node, data, size);
+          if (node->level > 0)
+            iblock_download_children (node, data, size);
+          ret = GNUNET_YES;
+        }
+    }
+  GNUNET_free (data);
+  return ret;
+}
+
+/**
+ * DOWNLOAD children of this GNUNET_EC_IBlock.
+ *
+ * @param node the node that should be downloaded
+ */
+static void
+iblock_download_children (const struct Node *node,
+                          const char *data, unsigned int size)
+{
+  struct GNUNET_GE_Context *ectx = node->ctx->ectx;
+  int i;
+  struct Node *child;
+  unsigned int childcount;
+  const GNUNET_EC_ContentHashKey *chks;
+  unsigned int levelSize;
+  unsigned long long baseOffset;
+
+  GNUNET_GE_ASSERT (ectx, node->level > 0);
+  childcount = size / sizeof (GNUNET_EC_ContentHashKey);
+  if (size != childcount * sizeof (GNUNET_EC_ContentHashKey))
+    {
+      GNUNET_GE_BREAK (ectx, 0);
+      return;
+    }
+  if (node->level == 1)
+    {
+      levelSize = GNUNET_ECRS_DBLOCK_SIZE;
+      baseOffset =
+        node->offset / sizeof (GNUNET_EC_ContentHashKey) *
+        GNUNET_ECRS_DBLOCK_SIZE;
+    }
+  else
+    {
+      levelSize =
+        sizeof (GNUNET_EC_ContentHashKey) * GNUNET_ECRS_CHK_PER_INODE;
+      baseOffset = node->offset * GNUNET_ECRS_CHK_PER_INODE;
+    }
+  chks = (const GNUNET_EC_ContentHashKey *) data;
+  for (i = 0; i < childcount; i++)
+    {
+      child = GNUNET_malloc (sizeof (struct Node));
+      child->ctx = node->ctx;
+      child->chk = chks[i];
+      child->offset = baseOffset + i * levelSize;
+      GNUNET_GE_ASSERT (ectx, child->offset < node->ctx->total);
+      child->level = node->level - 1;
+      GNUNET_GE_ASSERT (ectx, (child->level != 0) ||
+                        ((child->offset % GNUNET_ECRS_DBLOCK_SIZE) == 0));
+      if (GNUNET_NO == check_node_present (child))
+        add_request (child);
+      else
+        GNUNET_free (child);    /* done already! */
+    }
+}
+
+
+/**
+ * Decrypts a given data block
+ *
+ * @param data represents the data block
+ * @param hashcode represents the key concatenated with the initial
+ *        value used in the alg
+ * @param result where to store the result (encrypted block)
+ * @returns GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+static int
+decrypt_content (const char *data,
+                 unsigned int size, const GNUNET_HashCode * hashcode,
+                 char *result)
+{
+  GNUNET_AES_InitializationVector iv;
+  GNUNET_AES_SessionKey skey;
+
+  /* get key and init value from the GNUNET_HashCode */
+  GNUNET_hash_to_AES_key (hashcode, &skey, &iv);
+  return GNUNET_AES_decrypt (&skey, data, size, &iv, result);
+}
+
+/**
+ * We received a GNUNET_EC_ContentHashKey reply for a block. Decrypt.  Note
+ * that the caller (fslib) has already aquired the
+ * RM lock (we sometimes aquire it again in callees,
+ * mostly because our callees could be also be theoretically
+ * called from elsewhere).
+ *
+ * @param cls the node for which the reply is given, freed in
+ *        the function!
+ * @param query the query for which reply is the answer
+ * @param reply the reply
+ * @return GNUNET_OK if the reply was valid, GNUNET_SYSERR on error
+ */
+static int
+content_receive_callback (const GNUNET_HashCode * query,
+                          const GNUNET_DatastoreValue * reply, void *cls,
+                          unsigned long long uid)
+{
+  struct Node *node = cls;
+  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;
+  struct GNUNET_GE_Context *ectx = rm->ectx;
+  GNUNET_HashCode hc;
+  unsigned int size;
+  char *data;
+
+  if (rm->abortFlag != GNUNET_NO)
+    return GNUNET_SYSERR;
+  GNUNET_GE_ASSERT (ectx,
+                    0 == memcmp (query, &node->chk.query,
+                                 sizeof (GNUNET_HashCode)));
+  size = ntohl (reply->size) - sizeof (GNUNET_DatastoreValue);
+  if ((size <= sizeof (GNUNET_EC_DBlock)) ||
+      (size - sizeof (GNUNET_EC_DBlock) != get_node_size (node)))
+    {
+      GNUNET_GE_BREAK (ectx, 0);
+      return GNUNET_SYSERR;     /* invalid size! */
+    }
+  size -= sizeof (GNUNET_EC_DBlock);
+  data = GNUNET_malloc (size);
+  if (GNUNET_SYSERR ==
+      decrypt_content ((const char *)
+                       &((const GNUNET_EC_DBlock *) &reply[1])[1], size,
+                       &node->chk.key, data))
+    GNUNET_GE_ASSERT (ectx, 0);
+  GNUNET_hash (data, size, &hc);
+  if (0 != memcmp (&hc, &node->chk.key, sizeof (GNUNET_HashCode)))
+    {
+      GNUNET_free (data);
+      GNUNET_GE_BREAK (ectx, 0);
+      signal_abort (rm,
+                    _("Decrypted content does not match key. "
+                      "This is either a bug or a maliciously inserted "
+                      "file. Download aborted.\n"));
+      return GNUNET_SYSERR;
+    }
+  if (size != write_to_files (rm, node->level, node->offset, data, size))
+    {
+      GNUNET_GE_LOG_STRERROR (ectx,
+                              GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
+                              GNUNET_GE_USER | GNUNET_GE_BULK, "WRITE");
+      signal_abort (rm, _("IO error."));
+      return GNUNET_SYSERR;
+    }
+  notify_client_about_progress (node, data, size);
+  if (node->level > 0)
+    iblock_download_children (node, data, size);
+  GNUNET_free (data);
+  /* request satisfied, stop requesting! */
+  delete_node (node);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Helper function to sanitize filename
+ * and create necessary directories.
+ */
+static char *
+get_real_download_filename (struct GNUNET_GE_Context *ectx,
+                            const char *filename)
+{
+  struct stat buf;
+  char *realFN;
+  char *path;
+  char *pos;
+
+  if ((filename[strlen (filename) - 1] == '/') ||
+      (filename[strlen (filename) - 1] == '\\'))
+    {
+      realFN =
+        GNUNET_malloc (strlen (filename) + strlen (GNUNET_DIRECTORY_EXT));
+      strcpy (realFN, filename);
+      realFN[strlen (filename) - 1] = '\0';
+      strcat (realFN, GNUNET_DIRECTORY_EXT);
+    }
+  else
+    {
+      realFN = GNUNET_strdup (filename);
+    }
+  path = GNUNET_malloc (strlen (realFN) * strlen (GNUNET_DIRECTORY_EXT) + 1);
+  strcpy (path, realFN);
+  pos = path;
+  while (*pos != '\0')
+    {
+      if (*pos == DIR_SEPARATOR)
+        {
+          *pos = '\0';
+          if ((0 == STAT (path, &buf)) && (!S_ISDIR (buf.st_mode)))
+            {
+              *pos = DIR_SEPARATOR;
+              memmove (pos + strlen (GNUNET_DIRECTORY_EXT),
+                       pos, strlen (pos));
+              memcpy (pos,
+                      GNUNET_DIRECTORY_EXT, strlen (GNUNET_DIRECTORY_EXT));
+              pos += strlen (GNUNET_DIRECTORY_EXT);
+            }
+          else
+            {
+              *pos = DIR_SEPARATOR;
+            }
+        }
+      pos++;
+    }
+  GNUNET_free (realFN);
+  return path;
+}
+
+/* ***************** main method **************** */
+
+
+/**
+ * Download parts of a file.  Note that this will store
+ * the blocks at the respective offset in the given file.
+ * Also, the download is still using the blocking of the
+ * underlying ECRS encoding.  As a result, the download
+ * may *write* outside of the given boundaries (if offset
+ * and length do not match the 32k ECRS block boundaries).
+ * <p>
+ *
+ * This function should be used to focus a download towards a
+ * particular portion of the file (optimization), not to strictly
+ * limit the download to exactly those bytes.
+ *
+ * @param uri the URI of the file (determines what to download)
+ * @param filename where to store the file
+ * @param no_temporaries set to GNUNET_YES to disallow generation of temporary 
files
+ * @param start starting offset
+ * @param length length of the download (starting at offset)
+ */
+struct GNUNET_ECRS_DownloadContext *
+GNUNET_ECRS_file_download_partial_start (struct GNUNET_GE_Context *ectx,
+                                         struct GNUNET_GC_Configuration *cfg,
+                                         struct GNUNET_FS_SearchContext *sc,
+                                         const struct GNUNET_ECRS_URI *uri,
+                                         const char *filename,
+                                         unsigned long long offset,
+                                         unsigned long long length,
+                                         unsigned int anonymityLevel,
+                                         int no_temporaries,
+                                         GNUNET_ECRS_DownloadProgressCallback
+                                         dpcb, void *dpcbClosure)
+{
+  struct GNUNET_ECRS_DownloadContext *rm;
+  struct stat buf;
+  struct Node *top;
+  int ret;
+
+  if ((!GNUNET_ECRS_uri_test_chk (uri)) && (!GNUNET_ECRS_uri_test_loc (uri)))
+    {
+      GNUNET_GE_BREAK (ectx, 0);
+      return NULL;
+    }
+  rm = GNUNET_malloc (sizeof (struct GNUNET_ECRS_DownloadContext));
+  memset (rm, 0, sizeof (struct GNUNET_ECRS_DownloadContext));
+  if (sc == NULL)
+    {
+      rm->sctx = GNUNET_FS_create_search_context (ectx, cfg);
+      if (rm->sctx == NULL)
+        {
+          GNUNET_free (rm);
+          return NULL;
+        }
+      rm->my_sctx = GNUNET_YES;
+    }
+  else
+    {
+      rm->sctx = sc;
+      rm->my_sctx = GNUNET_NO;
+    }
+  rm->ectx = ectx;
+  rm->cfg = cfg;
+  rm->startTime = GNUNET_get_time ();
+  rm->anonymityLevel = anonymityLevel;
+  rm->offset = offset;
+  rm->length = length;
+  rm->dpcb = dpcb;
+  rm->dpcbClosure = dpcbClosure;
+  rm->main = GNUNET_thread_get_self ();
+  rm->total = GNUNET_ntohll (uri->data.fi.file_length);
+  rm->filename =
+    filename != NULL ? get_real_download_filename (ectx, filename) : NULL;
+
+  if ((rm->filename != NULL) &&
+      (GNUNET_SYSERR ==
+       GNUNET_disk_directory_create_for_file (ectx, rm->filename)))
+    {
+      free_request_manager (rm);
+      return NULL;
+    }
+  if (0 == rm->total)
+    {
+      if (rm->filename != NULL)
+        {
+          ret = GNUNET_disk_file_open (ectx,
+                                       rm->filename,
+                                       O_CREAT | O_WRONLY | O_TRUNC,
+                                       S_IRUSR | S_IWUSR);
+          if (ret == -1)
+            {
+              free_request_manager (rm);
+              return NULL;
+            }
+          CLOSE (ret);
+        }
+      dpcb (0, 0, rm->startTime, 0, NULL, 0, dpcbClosure);
+      free_request_manager (rm);
+      return NULL;
+    }
+  rm->treedepth = GNUNET_ECRS_compute_depth (rm->total);
+  if ((NULL != rm->filename) &&
+      ((0 == STAT (rm->filename, &buf))
+       && ((size_t) buf.st_size > rm->total)))
+    {
+      /* if exists and oversized, truncate */
+      if (truncate (rm->filename, rm->total) != 0)
+        {
+          GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                       GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
+                                       GNUNET_GE_BULK, "truncate",
+                                       rm->filename);
+          free_request_manager (rm);
+          return NULL;
+        }
+    }
+  if (rm->filename != NULL)
+    {
+      rm->handle = GNUNET_disk_file_open (ectx,
+                                          rm->filename,
+                                          O_CREAT | O_RDWR,
+                                          S_IRUSR | S_IWUSR);
+      if (rm->handle < 0)
+        {
+          free_request_manager (rm);
+          return NULL;
+        }
+    }
+  else
+    rm->handle = -1;
+  if (GNUNET_ECRS_uri_test_loc (uri))
+    {
+      GNUNET_hash (&uri->data.loc.peer, sizeof (GNUNET_RSA_PublicKey),
+                   &rm->target.hashPubKey);
+      rm->have_target = GNUNET_YES;
+    }
+  top = GNUNET_malloc (sizeof (struct Node));
+  memset (top, 0, sizeof (struct Node));
+  top->ctx = rm;
+  top->chk = uri->data.fi.chk;
+  top->offset = 0;
+  top->level = rm->treedepth;
+  if (GNUNET_NO == check_node_present (top))
+    add_request (top);
+  else
+    GNUNET_free (top);
+  return rm;
+}
+
+int
+GNUNET_ECRS_file_download_partial_stop (struct GNUNET_ECRS_DownloadContext
+                                        *rm)
+{
+  int ret;
+
+  ret = rm->abortFlag;
+  free_request_manager (rm);
+  if (ret == GNUNET_NO)
+    ret = GNUNET_OK;            /* normal termination */
+  return ret;
+}
+
+/**
+ * Download parts of a file.  Note that this will store
+ * the blocks at the respective offset in the given file.
+ * Also, the download is still using the blocking of the
+ * underlying ECRS encoding.  As a result, the download
+ * may *write* outside of the given boundaries (if offset
+ * and length do not match the 32k ECRS block boundaries).
+ * <p>
+ *
+ * This function should be used to focus a download towards a
+ * particular portion of the file (optimization), not to strictly
+ * limit the download to exactly those bytes.
+ *
+ * @param uri the URI of the file (determines what to download)
+ * @param filename where to store the file
+ * @param no_temporaries set to GNUNET_YES to disallow generation of temporary 
files
+ * @param start starting offset
+ * @param length length of the download (starting at offset)
+ */
+int
+GNUNET_ECRS_file_download_partial (struct GNUNET_GE_Context *ectx,
+                                   struct GNUNET_GC_Configuration *cfg,
+                                   const struct GNUNET_ECRS_URI *uri,
+                                   const char *filename,
+                                   unsigned long long offset,
+                                   unsigned long long length,
+                                   unsigned int anonymityLevel,
+                                   int no_temporaries,
+                                   GNUNET_ECRS_DownloadProgressCallback dpcb,
+                                   void *dpcbClosure,
+                                   GNUNET_ECRS_TestTerminate tt,
+                                   void *ttClosure)
+{
+  struct GNUNET_ECRS_DownloadContext *rm;
+  int ret;
+
+  if (length == 0)
+    return GNUNET_OK;
+  rm = GNUNET_ECRS_file_download_partial_start (ectx,
+                                                cfg,
+                                                NULL,
+                                                uri,
+                                                filename,
+                                                offset,
+                                                length,
+                                                anonymityLevel,
+                                                no_temporaries,
+                                                dpcb, dpcbClosure);
+  if (rm == NULL)
+    return GNUNET_SYSERR;
+  while ((GNUNET_OK == tt (ttClosure)) &&
+         (GNUNET_YES != GNUNET_shutdown_test ()) &&
+         (rm->abortFlag == GNUNET_NO) && (rm->head != NULL))
+    GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);
+  ret = GNUNET_ECRS_file_download_partial_stop (rm);
+  return ret;
+}
+
+/**
+ * Download a file (simplified API).
+ *
+ * @param uri the URI of the file (determines what to download)
+ * @param filename where to store the file
+ */
+int
+GNUNET_ECRS_file_download (struct GNUNET_GE_Context *ectx,
+                           struct GNUNET_GC_Configuration *cfg,
+                           const struct GNUNET_ECRS_URI *uri,
+                           const char *filename,
+                           unsigned int anonymityLevel,
+                           GNUNET_ECRS_DownloadProgressCallback dpcb,
+                           void *dpcbClosure, GNUNET_ECRS_TestTerminate tt,
+                           void *ttClosure)
+{
+  return GNUNET_ECRS_file_download_partial (ectx,
+                                            cfg,
+                                            uri,
+                                            filename,
+                                            0,
+                                            GNUNET_ECRS_uri_get_file_size
+                                            (uri), anonymityLevel, GNUNET_NO,
+                                            dpcb, dpcbClosure, tt, ttClosure);
+}
+
+/* end of download.c */

Added: gnunet/src/fs/fs_file_information.c
===================================================================
--- gnunet/src/fs/fs_file_information.c                         (rev 0)
+++ gnunet/src/fs/fs_file_information.c 2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,269 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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 fs/fs_file_information.c
+ * @brief  Manage information for publishing directory hierarchies
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_fs_service.h"
+#include "fs.h"
+
+
+/**
+ * Create an entry for a file in a publish-structure.
+ *
+ * @param filename name of the file or directory to publish
+ * @param meta metadata for the file
+ * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
+ *                GNUNET_SYSERR for simulation
+ * @param anonymity what is the desired anonymity level for sharing?
+ * @param priority what is the priority for OUR node to
+ *   keep this file available?  Use 0 for maximum anonymity and
+ *   minimum reliability...
+ * @param expirationTime when should this content expire?
+ * @return publish structure entry for the file
+ */
+struct GNUNET_FS_FileInformation *
+GNUNET_FS_file_information_create_from_file (void *client_info,
+                                            const char *filename,
+                                            const struct 
GNUNET_CONTAINER_MetaData *meta,
+                                            int do_index,
+                                            unsigned int anonymity,
+                                            unsigned int priority,
+                                            struct GNUNET_TIME_Absolute 
expirationTime)
+{
+  return NULL;
+}
+
+/**
+ * Create an entry for a file in a publish-structure.
+ *
+ * @param length length of the file
+ * @param data data for the file (should not be used afterwards by
+ *        the caller; caller will "free")
+ * @param meta metadata for the file
+ * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
+ *                GNUNET_SYSERR for simulation
+ * @param anonymity what is the desired anonymity level for sharing?
+ * @param priority what is the priority for OUR node to
+ *   keep this file available?  Use 0 for maximum anonymity and
+ *   minimum reliability...
+ * @param expirationTime when should this content expire?
+ * @return publish structure entry for the file
+ */
+struct GNUNET_FS_FileInformation *
+GNUNET_FS_file_information_create_from_data (void *client_info,
+                                            uint64_t length,
+                                            void *data,
+                                            const struct 
GNUNET_CONTAINER_MetaData *meta,
+                                            int do_index,
+                                            unsigned int anonymity,
+                                            unsigned int priority,
+                                            struct GNUNET_TIME_Absolute 
expirationTime)
+{
+  return NULL;
+}
+
+
+/**
+ * Create an entry for a file in a publish-structure.
+ *
+ * @param length length of the file
+ * @param reader function that can be used to obtain the data for the file 
+ * @param reader_cls closure for "reader"
+ * @param keywords under which keywords should this file be available
+ *         directly; can be NULL
+ * @param meta metadata for the file
+ * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
+ *                GNUNET_SYSERR for simulation
+ * @param anonymity what is the desired anonymity level for sharing?
+ * @param priority what is the priority for OUR node to
+ *   keep this file available?  Use 0 for maximum anonymity and
+ *   minimum reliability...
+ * @param expirationTime when should this content expire?
+ * @return publish structure entry for the file
+ */
+struct GNUNET_FS_FileInformation *
+GNUNET_FS_file_information_create_from_reader (void *client_info,
+                                              uint64_t length,
+                                              GNUNET_FS_DataReader reader,
+                                              void *reader_cls,
+                                              const struct GNUNET_FS_Uri 
*keywords,
+                                              const struct 
GNUNET_CONTAINER_MetaData *meta,
+                                              int do_index,
+                                              unsigned int anonymity,
+                                              unsigned int priority,
+                                              struct GNUNET_TIME_Absolute 
expirationTime)
+{
+  return NULL;
+}
+
+
+
+/**
+ * Simple, useful default implementation of a directory scanner
+ * (GNUNET_FS_DirectoryScanner).  This implementation expects to get a
+ * UNIX filename, will publish all files in the directory except hidden
+ * files (those starting with a ".").  Metadata will be extracted
+ * using GNU libextractor; the specific list of plugins should be
+ * specified in "cls", passing NULL will disable (!)  metadata
+ * extraction.  Keywords will be derived from the metadata and be
+ * subject to default canonicalization.  This is strictly a
+ * convenience function.
+ *
+ * @param cls must be of type "struct EXTRACTOR_Extractor*"
+ * @param dirname name of the directory to scan
+ * @param proc function called on each entry
+ * @param proc_cls closure for proc
+ * @param emsg where to store an error message (on errors)
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_FS_directory_scanner_default (void *cls,
+                                    const char *dirname,
+                                    GNUNET_FS_FileProcessor proc,
+                                    void *proc_cls)
+{
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Create a publish-structure from an existing file hierarchy, inferring
+ * and organizing keywords and metadata as much as possible.  This
+ * function primarily performs the recursive build and re-organizes
+ * keywords and metadata; for automatically getting metadata
+ * extraction, scanning of directories and creation of the respective
+ * GNUNET_FS_FileInformation entries the default scanner should be
+ * passed (GNUNET_FS_directory_scanner_default).  This is strictly a
+ * convenience function.
+ *
+ * @param filename name of the top-level file or directory
+ * @param scanner function used to get a list of files in a directory
+ * @param scanner_cls closure for scanner
+ * @param anonymity what is the desired anonymity level for sharing?
+ * @param priority what is the priority for OUR node to
+ *   keep this file available?  Use 0 for maximum anonymity and
+ *   minimum reliability...
+ * @param expirationTime when should this content expire?
+ * @return publish structure entry for the directory, NULL on error
+ */
+struct GNUNET_FS_FileInformation *
+GNUNET_FS_file_information_create_from_directory (void *client_info,
+                                                 GNUNET_FS_DirectoryScanner 
scanner,
+                                                 void *scanner_cls,
+                                                 unsigned int anonymity,
+                                                 unsigned int priority,
+                                                 struct GNUNET_TIME_Absolute 
expirationTime)
+{
+  return NULL;
+}
+
+
+/**
+ * Create an entry for an empty directory in a publish-structure.
+ * This function should be used by applications for which the
+ * use of "GNUNET_FS_file_information_create_from_directory"
+ * is not appropriate.
+ *
+ * @param meta metadata for the directory
+ * @param keywords under which keywords should this directory be available
+ *         directly; can be NULL
+ * @param anonymity what is the desired anonymity level for sharing?
+ * @param priority what is the priority for OUR node to
+ *   keep this file available?  Use 0 for maximum anonymity and
+ *   minimum reliability...
+ * @param expirationTime when should this content expire?
+ * @return publish structure entry for the directory , NULL on error
+ */
+struct GNUNET_FS_FileInformation *
+GNUNET_FS_file_information_create_empty_directory (void *client_info,
+                                                  const struct 
GNUNET_CONTAINER_MetaData *meta,
+                                                  const struct GNUNET_FS_Uri 
*keywords,
+                                                  unsigned int anonymity,
+                                                  unsigned int priority,
+                                                  struct GNUNET_TIME_Absolute 
expirationTime)
+{
+  return NULL;
+}
+
+
+/**
+ * Add an entry to a directory in a publish-structure.  Clients
+ * should never modify publish structures that were passed to
+ * "GNUNET_FS_publish_start" already.
+ *
+ * @param dir the directory
+ * @param end the entry to add; the entry must not have been
+ *            added to any other directory at this point and 
+ *            must not include "dir" in its structure
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir,
+                               struct GNUNET_FS_FileInformation *end)
+{
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Inspect a file or directory in a publish-structure.  Clients
+ * should never modify publish structures that were passed to
+ * "GNUNET_FS_publish_start" already.  When called on a directory,
+ * this function will FIRST call "proc" with information about
+ * the directory itself and then for each of the files in the
+ * directory (but not for files in subdirectories).  When called
+ * on a file, "proc" will be called exactly once (with information
+ * about the specific file).
+ *
+ * @param dir the directory
+ * @param proc function to call on each entry
+ * @param proc_cls closure for proc
+ */
+void
+GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir,
+                                   GNUNET_FS_FileInformationProcessor proc,
+                                   void *proc_cls)
+{
+}
+
+
+/**
+ * Destroy publish-structure.  Clients should never destroy publish
+ * structures that were passed to "GNUNET_FS_publish_start" already.
+ *
+ * @param fi structure to destroy
+ * @param cleaner function to call on each entry in the structure
+ *        (useful to clean up client_info); can be NULL; return
+ *        values are ignored
+ * @param cleaner_cls closure for cleaner
+ */
+void
+GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi,
+                                   GNUNET_FS_FileInformationProcessor cleaner,
+                                   void *cleaner_cls)
+{
+}
+
+
+/* end of fs_file_information.c */

Added: gnunet/src/fs/fs_namespace.c
===================================================================
--- gnunet/src/fs/fs_namespace.c                                (rev 0)
+++ gnunet/src/fs/fs_namespace.c        2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,729 @@
+/*
+     This file is part of GNUnet
+     (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 fs/fs_namespace.c
+ * @brief create and destroy namespaces
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_fs_service.h"
+
+
+/**
+ * Publish an advertismement for a namespace.  
+ *
+ * @param h handle to the file sharing subsystem
+ * @param namespace handle for the namespace that should be advertised
+ * @param meta meta-data for the namespace advertisement
+ * @param anonymity for the namespace advertismement
+ * @param priority for the namespace advertisement
+ * @param expiration for the namespace advertisement
+ * @param advertisementURI the keyword (!) URI to advertise the
+ *        namespace under (we will create a GNUNET_EC_KNBlock)
+ * @param rootEntry name of the root entry in the namespace (for
+ *        the namespace advertisement)
+ *
+ * @return uri of the advertisement
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
+                              struct GNUNET_FS_Namespace *namespace,
+                              const struct GNUNET_MetaData *meta,
+                              unsigned int anonymity,
+                              unsigned int priority,
+                              struct GNUNET_TIME_Absolute expiration,
+                              const struct GNUNET_FS_Uri *advertisementURI,
+                              const char *rootEntry)
+{
+  return NULL;
+}
+
+
+/**
+ * Create a namespace with the given name; if one already
+ * exists, return a handle to the existing namespace.
+ *
+ * @param h handle to the file sharing subsystem
+ * @param name name to use for the namespace
+ * @return handle to the namespace, NULL on error
+ */
+struct GNUNET_FS_Namespace *
+GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h,
+                           const char *name)
+{
+  return NULL;
+}
+
+
+/**
+ * Delete a namespace handle.  Can be used for a clean shutdown (free
+ * memory) or also to freeze the namespace to prevent further
+ * insertions by anyone.
+ *
+ * @param namespace handle to the namespace that should be deleted / freed
+ * @param freeze prevents future insertions; creating a namespace
+ *        with the same name again will create a fresh namespace instead
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int 
+GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace,
+                           int freeze)
+{
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Build a list of all available local (!) namespaces The returned
+ * names are only the nicknames since we only iterate over the local
+ * namespaces.
+ *
+ * @param h handle to the file sharing subsystem
+ * @param cb function to call on each known namespace
+ * @param cb_cls closure for cb
+ */
+void 
+GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
+                         GNUNET_FS_NamespaceInfoProcessor cb,
+                         void *cb_cls)
+{
+}
+
+/* end of fs_namespace.c */
+
+#if 0
+/*
+     This file is part of GNUnet
+     (C) 2004, 2005, 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/namespace.c
+ * @brief creation, deletion and advertising of namespaces
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_directories.h"
+#include "gnunet_protocols.h"
+#include "gnunet_ecrs_lib.h"
+#include "gnunet_fs_lib.h"
+#include "ecrs_core.h"
+#include "ecrs.h"
+
+#define PSEUDODIR "data/namespace/keys/"
+#define INITVALUE "GNUnet!!"
+#define MAX_SBLOCK_SIZE 32000
+
+static char *
+getPseudonymFileName (struct GNUNET_GE_Context *ectx,
+                      struct GNUNET_GC_Configuration *cfg,
+                      const GNUNET_HashCode * pid)
+{
+  char *gnHome;
+  char *fileName;
+  GNUNET_EncName enc;
+
+  GNUNET_GC_get_configuration_value_filename (cfg,
+                                              "GNUNET",
+                                              "GNUNET_HOME",
+                                              GNUNET_DEFAULT_HOME_DIRECTORY,
+                                              &fileName);
+  gnHome = GNUNET_expand_file_name (ectx, fileName);
+  GNUNET_free (fileName);
+  fileName =
+    GNUNET_malloc (strlen (gnHome) + strlen (PSEUDODIR) +
+                   sizeof (GNUNET_EncName) + 2);
+  strcpy (fileName, gnHome);
+  GNUNET_free (gnHome);
+  strcat (fileName, DIR_SEPARATOR_STR);
+  strcat (fileName, PSEUDODIR);
+  GNUNET_disk_directory_create (ectx, fileName);
+  if (pid != NULL)
+    {
+      GNUNET_hash_to_enc (pid, &enc);
+      strcat (fileName, (char *) &enc);
+    }
+  return fileName;
+}
+
+
+/**
+ * Check if the given namespace exists (locally).
+ *
+ * @return GNUNET_OK if the namespace exists, GNUNET_SYSERR if not
+ */
+int
+GNUNET_ECRS_namespace_test_exists (struct GNUNET_GE_Context *ectx,
+                                   struct GNUNET_GC_Configuration *cfg,
+                                   const GNUNET_HashCode * pid)
+{
+  char *fileName;
+  int ret;
+
+  fileName = getPseudonymFileName (ectx, cfg, pid);
+  ret = GNUNET_disk_file_test (ectx, fileName);
+  GNUNET_free (fileName);
+  return ret;
+}
+
+/**
+ * Delete a local namespace.
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_ECRS_namespace_delete (struct GNUNET_GE_Context *ectx,
+                              struct GNUNET_GC_Configuration *cfg,
+                              const GNUNET_HashCode * pid)
+{
+  char *fileName;
+
+  fileName = getPseudonymFileName (ectx, cfg, pid);
+  if (GNUNET_YES != GNUNET_disk_file_test (ectx, fileName))
+    {
+      GNUNET_free (fileName);
+      return GNUNET_SYSERR;     /* no such namespace */
+    }
+  if (0 != UNLINK (fileName))
+    {
+      GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                   GNUNET_GE_WARNING | GNUNET_GE_USER |
+                                   GNUNET_GE_BULK, "unlink", fileName);
+      GNUNET_free (fileName);
+      return GNUNET_SYSERR;
+    }
+  GNUNET_free (fileName);
+  return GNUNET_OK;
+}
+
+/**
+ * Write the private key of the namespace to a file.
+ */
+static int
+write_namespace_key (struct GNUNET_GC_Configuration *cfg,
+                     const struct GNUNET_RSA_PrivateKey *key)
+{
+  GNUNET_RSA_PrivateKeyEncoded *namespace_priv_key_encoded;
+  char *fileName;
+  GNUNET_RSA_PublicKey pubk;
+  GNUNET_HashCode pid;
+
+  GNUNET_RSA_get_public_key (key, &pubk);
+  GNUNET_hash (&pubk, sizeof (GNUNET_RSA_PublicKey), &pid);
+  fileName = getPseudonymFileName (NULL, cfg, &pid);
+  if (GNUNET_YES == GNUNET_disk_file_test (NULL, fileName))
+    {
+      GNUNET_GE_BREAK (NULL, 0);        /* hash collision!? */
+      GNUNET_free (fileName);
+      return GNUNET_SYSERR;
+    }
+  namespace_priv_key_encoded = GNUNET_RSA_encode_key (key);
+  GNUNET_disk_file_write (NULL, fileName,
+                          (const char *) namespace_priv_key_encoded,
+                          ntohs (namespace_priv_key_encoded->len), "600");
+  GNUNET_free (fileName);
+  GNUNET_free (namespace_priv_key_encoded);
+  return GNUNET_OK;
+}
+
+/**
+ * Create a new namespace (and publish an advertismement).
+ * This publishes both an GNUNET_EC_NBlock in the namespace itself
+ * as well as KNBlocks under all keywords specified in
+ * the advertisementURI.
+ *
+ * @param anonymity_level for the namespace advertismement
+ * @param priority for the namespace advertisement
+ * @param expiration for the namespace advertisement
+ * @param advertisementURI the keyword (!) URI to advertise the
+ *        namespace under (GNUNET_EC_KNBlock)
+ * @param meta meta-data for the namespace advertisement
+ *        (will be used to derive a name)
+ * @param rootEntry name of the root entry in the namespace (for
+ *        the namespace advertisement)
+ * @param rootURI set to the URI of the namespace, NULL if
+ *        no advertisement was created
+ *
+ * @return URI on success, NULL on error
+ */
+struct GNUNET_ECRS_URI *
+GNUNET_ECRS_namespace_create (struct GNUNET_GE_Context *ectx,
+                              struct GNUNET_GC_Configuration *cfg,
+                              const struct GNUNET_MetaData *meta,
+                              unsigned int anonymityLevel,
+                              unsigned int priority,
+                              GNUNET_CronTime expiration,
+                              const struct GNUNET_ECRS_URI *advertisementURI,
+                              const char *rootEntry)
+{
+  struct GNUNET_ECRS_URI *rootURI;
+  struct GNUNET_RSA_PrivateKey *namespace_priv_key;
+  GNUNET_HashCode hc;
+  struct GNUNET_ClientServerConnection *sock;
+  GNUNET_DatastoreValue *value;
+  GNUNET_DatastoreValue *knvalue;
+  unsigned int size;
+  unsigned int mdsize;
+  struct GNUNET_RSA_PrivateKey *pk;
+  GNUNET_EC_SBlock *sb;
+  GNUNET_EC_KSBlock *ksb;
+  char **keywords;
+  const char *keyword;
+  unsigned int keywordCount;
+  int i;
+  char *cpy;
+  char *rtgt;
+
+  if ((advertisementURI != NULL)
+      && (!GNUNET_ECRS_uri_test_ksk (advertisementURI)))
+    {
+      GNUNET_GE_BREAK (ectx, 0);
+      return NULL;
+    }
+  namespace_priv_key = GNUNET_RSA_create_key ();
+  if (GNUNET_OK != write_namespace_key (cfg, namespace_priv_key))
+    {
+      GNUNET_RSA_free_key (namespace_priv_key);
+      return NULL;
+    }
+
+  /* create advertisements */
+  mdsize = GNUNET_meta_data_get_serialized_size (meta, GNUNET_SERIALIZE_PART);
+  size = mdsize + sizeof (GNUNET_EC_SBlock) + strlen (rootEntry) + 2;
+  if (size > MAX_SBLOCK_SIZE)
+    {
+      size = MAX_SBLOCK_SIZE;
+      mdsize = size - sizeof (GNUNET_EC_SBlock) - strlen (rootEntry) - 2;
+    }
+  value = GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + size);
+  memset (value, 0, sizeof (GNUNET_DatastoreValue) + size);
+  sb = (GNUNET_EC_SBlock *) & value[1];
+  sb->type = htonl (GNUNET_ECRS_BLOCKTYPE_SIGNED);
+  GNUNET_RSA_get_public_key (namespace_priv_key, &sb->subspace);
+  rtgt = (char *) &sb[1];
+  memcpy (rtgt, rootEntry, strlen (rootEntry) + 1);
+  mdsize = GNUNET_meta_data_serialize (ectx,
+                                       meta,
+                                       &rtgt[strlen (rootEntry) + 2],
+                                       mdsize, GNUNET_SERIALIZE_PART);
+  if (mdsize == -1)
+    {
+      GNUNET_GE_BREAK (ectx, 0);
+      GNUNET_RSA_free_key (namespace_priv_key);
+      GNUNET_free (value);
+      return NULL;
+    }
+  size = mdsize + sizeof (GNUNET_EC_SBlock) + strlen (rootEntry) + 2;
+  GNUNET_GE_ASSERT (ectx,
+                    GNUNET_OK == GNUNET_RSA_sign (namespace_priv_key,
+                                                  size
+                                                  -
+                                                  sizeof
+                                                  (GNUNET_RSA_Signature) -
+                                                  sizeof
+                                                  (GNUNET_RSA_PublicKey) -
+                                                  sizeof (unsigned int),
+                                                  &sb->identifier,
+                                                  &sb->signature));
+  value->size = htonl (sizeof (GNUNET_DatastoreValue) + size);
+  value->type = htonl (GNUNET_ECRS_BLOCKTYPE_SIGNED);
+  value->priority = htonl (priority);
+  value->anonymity_level = htonl (anonymityLevel);
+  value->expiration_time = GNUNET_htonll (expiration);
+  sock = GNUNET_client_connection_create (ectx, cfg);
+  if (sock == NULL)
+    {
+      GNUNET_free (value);
+      GNUNET_RSA_free_key (namespace_priv_key);
+      return NULL;
+    }
+  if (GNUNET_OK != GNUNET_FS_insert (sock, value))
+    {
+      GNUNET_free (value);
+      GNUNET_client_connection_destroy (sock);
+      GNUNET_RSA_free_key (namespace_priv_key);
+      return NULL;
+    }
+
+
+  /* publish KNBlocks */
+  size += sizeof (GNUNET_EC_KSBlock) - sizeof (GNUNET_EC_SBlock);
+  knvalue = GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + size);
+  *knvalue = *value;
+  knvalue->type = htonl (GNUNET_ECRS_BLOCKTYPE_KEYWORD_SIGNED);
+  knvalue->size = htonl (sizeof (GNUNET_DatastoreValue) + size);
+  ksb = (GNUNET_EC_KSBlock *) & knvalue[1];
+  ksb->type = htonl (GNUNET_ECRS_BLOCKTYPE_KEYWORD_SIGNED);
+  memcpy (&ksb->sblock,
+          sb, sizeof (GNUNET_EC_SBlock) + mdsize + strlen (rootEntry) + 2);
+
+  if (advertisementURI != NULL)
+    {
+      keywords = advertisementURI->data.ksk.keywords;
+      keywordCount = advertisementURI->data.ksk.keywordCount;
+      cpy =
+        GNUNET_malloc (size - sizeof (GNUNET_EC_KBlock) -
+                       sizeof (unsigned int));
+      memcpy (cpy,
+              &ksb->sblock,
+              size - sizeof (GNUNET_EC_KBlock) - sizeof (unsigned int));
+      for (i = 0; i < keywordCount; i++)
+        {
+          keyword = keywords[i];
+          /* first character of keyword indicates
+             mandatory or not -- ignore for hashing! */
+          GNUNET_hash (&keyword[1], strlen (&keyword[1]), &hc);
+          pk = GNUNET_RSA_create_key_from_hash (&hc);
+          GNUNET_RSA_get_public_key (pk, &ksb->kblock.keyspace);
+          GNUNET_GE_ASSERT (ectx,
+                            size - sizeof (GNUNET_EC_KBlock) -
+                            sizeof (unsigned int) ==
+                            sizeof (GNUNET_EC_SBlock) + mdsize +
+                            strlen (rootEntry) + 2);
+          GNUNET_ECRS_encryptInPlace (&hc, &ksb->sblock,
+                                      size - sizeof (GNUNET_EC_KBlock) -
+                                      sizeof (unsigned int));
+
+          GNUNET_GE_ASSERT (ectx,
+                            GNUNET_OK == GNUNET_RSA_sign (pk,
+                                                          size -
+                                                          sizeof
+                                                          (GNUNET_EC_KBlock) -
+                                                          sizeof (unsigned
+                                                                  int),
+                                                          &ksb->sblock,
+                                                          &ksb->
+                                                          kblock.signature));
+          /* extra check: verify sig */
+          GNUNET_RSA_free_key (pk);
+          if (GNUNET_OK != GNUNET_FS_insert (sock, knvalue))
+            {
+              GNUNET_GE_BREAK (ectx, 0);
+              GNUNET_free (cpy);
+              GNUNET_free (knvalue);
+              GNUNET_free (value);
+              GNUNET_client_connection_destroy (sock);
+              GNUNET_RSA_free_key (namespace_priv_key);
+              return NULL;
+            }
+          /* restore nblock to avoid re-encryption! */
+          memcpy (&ksb->sblock,
+                  cpy,
+                  size - sizeof (GNUNET_EC_KBlock) - sizeof (unsigned int));
+        }
+      GNUNET_free (cpy);
+    }
+  rootURI = GNUNET_malloc (sizeof (URI));
+  rootURI->type = sks;
+  GNUNET_hash (&sb->subspace,
+               sizeof (GNUNET_RSA_PublicKey), &rootURI->data.sks.namespace);
+  rootURI->data.sks.identifier = GNUNET_strdup (rootEntry);
+  GNUNET_free (knvalue);
+  GNUNET_free (value);
+  GNUNET_client_connection_destroy (sock);
+  GNUNET_RSA_free_key (namespace_priv_key);
+
+  return rootURI;
+}
+
+static struct GNUNET_RSA_PrivateKey *
+read_namespace_key (struct GNUNET_GC_Configuration *cfg,
+                    const GNUNET_HashCode * pid)
+{
+  char *fileName;
+  GNUNET_RSA_PrivateKeyEncoded *hke;
+  struct GNUNET_RSA_PrivateKey *hk;
+  char *dst;
+  unsigned long long len;
+
+  fileName = getPseudonymFileName (NULL, cfg, pid);
+  if (GNUNET_OK != GNUNET_disk_file_size (NULL, fileName, &len, GNUNET_YES))
+    {
+      GNUNET_free (fileName);
+      return NULL;
+    }
+  if (len < 2)
+    {
+      GNUNET_GE_LOG (NULL, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("File `%s' does not contain a pseudonym.\n"),
+                     fileName);
+      GNUNET_free (fileName);
+      return NULL;
+    }
+  dst = GNUNET_malloc (len);
+  len = GNUNET_disk_file_read (NULL, fileName, len, dst);
+  hke = (GNUNET_RSA_PrivateKeyEncoded *) dst;
+  if (ntohs (hke->len) != len)
+    {
+      GNUNET_GE_LOG (NULL, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Format of pseudonym `%s' is invalid.\n"), fileName);
+      GNUNET_free (fileName);
+      GNUNET_free (hke);
+      return NULL;
+    }
+  GNUNET_free (fileName);
+  hk = GNUNET_RSA_decode_key (hke);
+  GNUNET_free (hke);
+  return hk;
+}
+
+
+/**
+ * Add an entry into a namespace.
+ *
+ * @param dstU to which URI should the namespace entry refer?
+ * @param md what meta-data should be associated with the
+ *        entry?
+ * @param thisId name of this entry in the namespace (keyword/identifier)
+ * @param nextId name of the update for this entry (to be published in
+ *               the future; maybe NULL)
+ * @param pid unique identifier of the namespace/pseudonym
+ * @return URI on success, NULL on error
+ */
+struct GNUNET_ECRS_URI *
+GNUNET_ECRS_namespace_add_content (struct GNUNET_GE_Context *ectx,
+                                   struct GNUNET_GC_Configuration *cfg,
+                                   const GNUNET_HashCode * pid,
+                                   unsigned int anonymityLevel,
+                                   unsigned int priority,
+                                   GNUNET_CronTime expiration,
+                                   const char *thisId,
+                                   const char *nextId,
+                                   const struct GNUNET_ECRS_URI *dstU,
+                                   const struct GNUNET_MetaData *md)
+{
+  struct GNUNET_ECRS_URI *uri;
+  struct GNUNET_ClientServerConnection *sock;
+  GNUNET_DatastoreValue *value;
+  unsigned int size;
+  unsigned int mdsize;
+  struct GNUNET_RSA_PrivateKey *hk;
+  GNUNET_EC_SBlock *sb;
+  char *dstURI;
+  char *destPos;
+  GNUNET_HashCode hc;           /* hash of thisId = key */
+  GNUNET_HashCode hc2;          /* hash of hc = identifier */
+  int ret;
+  unsigned int nidlen;
+
+  hk = read_namespace_key (cfg, pid);
+  if (hk == NULL)
+    return NULL;
+
+  /* THEN: construct GNUNET_EC_SBlock */
+  dstURI = GNUNET_ECRS_uri_to_string (dstU);
+  mdsize = GNUNET_meta_data_get_serialized_size (md, GNUNET_SERIALIZE_PART);
+  if (nextId == NULL)
+    nextId = "";
+  nidlen = strlen (nextId) + 1;
+  size = mdsize + sizeof (GNUNET_EC_SBlock) + strlen (dstURI) + 1 + nidlen;
+  if (size > MAX_SBLOCK_SIZE)
+    {
+      size = MAX_SBLOCK_SIZE;
+      mdsize =
+        size - (sizeof (GNUNET_EC_SBlock) + strlen (dstURI) + 1 + nidlen);
+    }
+  value = GNUNET_malloc (sizeof (GNUNET_DatastoreValue) + size);
+  sb = (GNUNET_EC_SBlock *) & value[1];
+  sb->type = htonl (GNUNET_ECRS_BLOCKTYPE_SIGNED);
+  destPos = (char *) &sb[1];
+  memcpy (destPos, nextId, nidlen);
+  destPos += nidlen;
+  memcpy (destPos, dstURI, strlen (dstURI) + 1);
+  destPos += strlen (dstURI) + 1;
+  mdsize = GNUNET_meta_data_serialize (ectx,
+                                       md,
+                                       destPos,
+                                       mdsize, GNUNET_SERIALIZE_PART);
+  if (mdsize == -1)
+    {
+      GNUNET_GE_BREAK (ectx, 0);
+      GNUNET_free (dstURI);
+      GNUNET_RSA_free_key (hk);
+      GNUNET_free (value);
+      return NULL;
+    }
+  size = sizeof (GNUNET_EC_SBlock) + mdsize + strlen (dstURI) + 1 + nidlen;
+  value->size = htonl (sizeof (GNUNET_DatastoreValue) + size);
+  value->type = htonl (GNUNET_ECRS_BLOCKTYPE_SIGNED);
+  value->priority = htonl (priority);
+  value->anonymity_level = htonl (anonymityLevel);
+  value->expiration_time = GNUNET_htonll (expiration);
+  GNUNET_hash (thisId, strlen (thisId), &hc);
+  GNUNET_hash (&hc, sizeof (GNUNET_HashCode), &hc2);
+  uri = GNUNET_malloc (sizeof (URI));
+  uri->type = sks;
+  GNUNET_RSA_get_public_key (hk, &sb->subspace);
+  GNUNET_hash (&sb->subspace,
+               sizeof (GNUNET_RSA_PublicKey), &uri->data.sks.namespace);
+  GNUNET_GE_BREAK (ectx, 0 == memcmp (&uri->data.sks.namespace,
+                                      pid, sizeof (GNUNET_HashCode)));
+  uri->data.sks.identifier = GNUNET_strdup (thisId);
+  GNUNET_hash_xor (&hc2, &uri->data.sks.namespace, &sb->identifier);
+  GNUNET_ECRS_encryptInPlace (&hc, &sb[1], size - sizeof (GNUNET_EC_SBlock));
+  GNUNET_GE_ASSERT (ectx,
+                    GNUNET_OK == GNUNET_RSA_sign (hk,
+                                                  size
+                                                  -
+                                                  sizeof
+                                                  (GNUNET_RSA_Signature) -
+                                                  sizeof
+                                                  (GNUNET_RSA_PublicKey) -
+                                                  sizeof (unsigned int),
+                                                  &sb->identifier,
+                                                  &sb->signature));
+  GNUNET_RSA_free_key (hk);
+  sock = GNUNET_client_connection_create (ectx, cfg);
+  ret = GNUNET_FS_insert (sock, value);
+  if (ret != GNUNET_OK)
+    {
+      GNUNET_free (uri);
+      uri = NULL;
+    }
+  GNUNET_client_connection_destroy (sock);
+  GNUNET_free (value);
+  GNUNET_free (dstURI);
+
+  return uri;
+}
+
+struct lNCLS
+{
+  struct GNUNET_GE_Context *ectx;
+  struct GNUNET_GC_Configuration *cfg;
+  GNUNET_ECRS_NamespaceInfoProcessor cb;
+  void *cls;
+  int cnt;
+};
+
+static int
+processFile_ (void *cls, const char *fileName)
+{
+  struct lNCLS *c = cls;
+  struct GNUNET_RSA_PrivateKey *hk;
+  GNUNET_RSA_PrivateKeyEncoded *hke;
+  char *dst;
+  unsigned long long len;
+  GNUNET_HashCode namespace;
+  GNUNET_RSA_PublicKey pk;
+  const char *name;
+
+  if (GNUNET_OK !=
+      GNUNET_disk_file_size (c->ectx, fileName, &len, GNUNET_YES))
+    return GNUNET_OK;
+  if (len < 2)
+    {
+      GNUNET_GE_LOG (c->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Format of file `%s' is invalid, trying to remove.\n"),
+                     fileName);
+      UNLINK (fileName);
+      return GNUNET_OK;
+    }
+  dst = GNUNET_malloc (len);
+  len = GNUNET_disk_file_read (c->ectx, fileName, len, dst);
+  hke = (GNUNET_RSA_PrivateKeyEncoded *) dst;
+  if (ntohs (hke->len) != len)
+    {
+      GNUNET_GE_LOG (c->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Format of file `%s' is invalid, trying to remove.\n"),
+                     fileName);
+      UNLINK (fileName);
+      GNUNET_free (hke);
+      return GNUNET_OK;
+    }
+  hk = GNUNET_RSA_decode_key (hke);
+  GNUNET_free (hke);
+  if (hk == NULL)
+    {
+      GNUNET_GE_LOG (c->ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Format of file `%s' is invalid, trying to remove.\n"),
+                     fileName);
+      UNLINK (fileName);
+      GNUNET_GE_BREAK (c->ectx, 0);
+      return GNUNET_SYSERR;
+    }
+  GNUNET_RSA_get_public_key (hk, &pk);
+  GNUNET_RSA_free_key (hk);
+  GNUNET_hash (&pk, sizeof (GNUNET_RSA_PublicKey), &namespace);
+  if (NULL != c->cb)
+    {
+      name = fileName;
+      while (NULL != strstr (name, DIR_SEPARATOR_STR))
+        name = 1 + strstr (name, DIR_SEPARATOR_STR);
+      if (GNUNET_OK == c->cb (&namespace, name, c->cls))
+        c->cnt++;
+      else
+        c->cnt = GNUNET_SYSERR;
+    }
+  else
+    c->cnt++;
+  return GNUNET_OK;
+}
+
+/**
+ * Build a list of all available namespaces
+ *
+ * @param list where to store the names (is allocated, caller frees)
+ * @return GNUNET_SYSERR on error, otherwise the number of pseudonyms in list
+ */
+int
+GNUNET_ECRS_get_namespaces (struct GNUNET_GE_Context *ectx,
+                            struct GNUNET_GC_Configuration *cfg,
+                            GNUNET_ECRS_NamespaceInfoProcessor cb, void *cls)
+{
+  char *dirName;
+  struct lNCLS myCLS;
+
+  myCLS.cls = cls;
+  myCLS.cb = cb;
+  myCLS.cnt = 0;
+  myCLS.ectx = ectx;
+  myCLS.cfg = cfg;
+  dirName = getPseudonymFileName (ectx, cfg, NULL);
+  GNUNET_disk_directory_scan (ectx, dirName, &processFile_, &myCLS);
+  GNUNET_free (dirName);
+  return myCLS.cnt;
+}
+
+
+
+/* end of namespace.c */
+#endif

Added: gnunet/src/fs/fs_publish.c
===================================================================
--- gnunet/src/fs/fs_publish.c                          (rev 0)
+++ gnunet/src/fs/fs_publish.c  2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,459 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 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 fs/fs_publish.c
+ * @brief publish a file or directory in GNUnet
+ * @see http://gnunet.org/encoding.php3
+ * @author Krista Bennett
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_fs_service.h"
+#include "fs.h"
+
+#define DEBUG_PUBLISH GNUNET_YES
+
+
+
+#if 0
+
+/**
+ * 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 and clear the level.  iblocks is guaranteed to be big
+ * enough.
+ */
+static int
+pushBlock (struct GNUNET_ClientServerConnection *sock,
+           const GNUNET_EC_ContentHashKey * chk,
+           unsigned int level,
+           GNUNET_DatastoreValue ** iblocks,
+           unsigned int prio, GNUNET_CronTime expirationTime)
+{
+  unsigned int size;
+  unsigned int present;
+  GNUNET_DatastoreValue *value;
+  GNUNET_EC_DBlock *db;
+  GNUNET_EC_ContentHashKey ichk;
+
+  size = ntohl (iblocks[level]->size);
+  GNUNET_GE_ASSERT (NULL, size > sizeof (GNUNET_DatastoreValue));
+  size -= sizeof (GNUNET_DatastoreValue);
+  GNUNET_GE_ASSERT (NULL,
+                    size - sizeof (GNUNET_EC_DBlock) <=
+                    GNUNET_ECRS_IBLOCK_SIZE);
+  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, prio,
+                                  expirationTime))
+        return GNUNET_SYSERR;
+      GNUNET_EC_file_block_encode (db, size, &ichk.query, &value);
+      if (value == NULL)
+        {
+          GNUNET_GE_BREAK (NULL, 0);
+          return GNUNET_SYSERR;
+        }
+      value->priority = htonl (prio);
+      value->expiration_time = GNUNET_htonll (expirationTime);
+      if (GNUNET_OK != GNUNET_FS_insert (sock, value))
+        {
+          GNUNET_free (value);
+          return GNUNET_SYSERR;
+        }
+      GNUNET_free (value);
+      size = sizeof (GNUNET_EC_DBlock); /* type */
+    }
+  /* append GNUNET_EC_ContentHashKey */
+  memcpy (&((char *) db)[size], chk, sizeof (GNUNET_EC_ContentHashKey));
+  size += sizeof (GNUNET_EC_ContentHashKey) + sizeof (GNUNET_DatastoreValue);
+  GNUNET_GE_ASSERT (NULL, size < GNUNET_MAX_BUFFER_SIZE);
+  iblocks[level]->size = htonl (size);
+
+  return GNUNET_OK;
+}
+
+/**
+ * Index or insert a file.
+ *
+ * @param priority what is the priority for OUR node to
+ *   keep this file available?  Use 0 for maximum anonymity and
+ *   minimum reliability...
+ * @param doIndex GNUNET_YES for index, GNUNET_NO for insertion,
+ *         GNUNET_SYSERR for simulation
+ * @param uri set to the URI of the uploaded file
+ * @return GNUNET_SYSERR if the upload failed (i.e. not enough space
+ *  or gnunetd not running)
+ */
+int
+GNUNET_ECRS_file_upload (struct GNUNET_GE_Context *ectx,
+                         struct GNUNET_GC_Configuration *cfg,
+                         const char *filename,
+                         int doIndex,
+                         unsigned int anonymityLevel,
+                         unsigned int priority,
+                         GNUNET_CronTime expirationTime,
+                         GNUNET_ECRS_UploadProgressCallback upcb,
+                         void *upcbClosure,
+                         GNUNET_ECRS_TestTerminate tt,
+                         void *ttClosure, struct GNUNET_ECRS_URI **uri)
+{
+  unsigned long long filesize;
+  unsigned long long pos;
+  unsigned int treedepth;
+  int fd;
+  int i;
+  int ret;
+  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 mchk;
+  GNUNET_CronTime eta;
+  GNUNET_CronTime start;
+  GNUNET_CronTime now;
+  GNUNET_EC_FileIdentifier fid;
+#if DEBUG_UPLOAD
+  GNUNET_EncName enc;
+#endif
+
+  GNUNET_GE_ASSERT (ectx, cfg != NULL);
+  start = GNUNET_get_time ();
+  memset (&mchk, 0, sizeof (GNUNET_EC_ContentHashKey));
+  if (GNUNET_YES != GNUNET_disk_file_test (ectx, filename))
+    {
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("`%s' is not a file.\n"), filename);
+      return GNUNET_SYSERR;
+    }
+  if (GNUNET_OK !=
+      GNUNET_disk_file_size (ectx, filename, &filesize, GNUNET_YES))
+    {
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Cannot get size of file `%s'"), filename);
+
+      return GNUNET_SYSERR;
+    }
+  sock = GNUNET_client_connection_create (ectx, cfg);
+  if (sock == NULL)
+    {
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Failed to connect to gnunetd."));
+      return GNUNET_SYSERR;
+    }
+  eta = 0;
+  if (upcb != NULL)
+    upcb (filesize, 0, eta, upcbClosure);
+  if (doIndex == GNUNET_YES)
+    {
+      if (GNUNET_SYSERR == GNUNET_hash_file (ectx, filename, &fileId))
+        {
+          GNUNET_GE_LOG (ectx,
+                         GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                         _("Cannot hash `%s'.\n"), filename);
+
+          GNUNET_client_connection_destroy (sock);
+          return GNUNET_SYSERR;
+        }
+      if (GNUNET_YES == GNUNET_FS_test_indexed (sock, &fileId))
+        {
+          /* file already indexed; simulate only to get the URI! */
+          doIndex = GNUNET_SYSERR;
+        }
+    }
+  if (doIndex == GNUNET_YES)
+    {
+      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 */
+
+      switch (GNUNET_FS_prepare_to_index (sock, &fileId, filename))
+        {
+        case GNUNET_SYSERR:
+          GNUNET_GE_LOG (ectx,
+                         GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                         _("Initialization for indexing file `%s' failed.\n"),
+                         filename);
+          GNUNET_client_connection_destroy (sock);
+          return GNUNET_SYSERR;
+        case GNUNET_NO:
+          GNUNET_GE_LOG (ectx,
+                         GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                         _
+                         ("Indexing file `%s' failed. Suggestion: try to 
insert the file.\n"),
+                         filename);
+          GNUNET_client_connection_destroy (sock);
+          return GNUNET_SYSERR;
+        default:
+          break;
+        }
+    }
+  treedepth = GNUNET_ECRS_compute_depth (filesize);
+  fd = GNUNET_disk_file_open (ectx, filename, O_RDONLY | O_LARGEFILE);
+  if (fd == -1)
+    {
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("Cannot open file `%s': `%s'"), filename,
+                     STRERROR (errno));
+
+      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 (anonymityLevel);
+  dblock->priority = htonl (priority);
+  dblock->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
+  dblock->expiration_time = GNUNET_htonll (expirationTime);
+  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 (anonymityLevel);
+      iblocks[i]->priority = htonl (priority);
+      iblocks[i]->type = htonl (GNUNET_ECRS_BLOCKTYPE_DATA);
+      iblocks[i]->expiration_time = GNUNET_htonll (expirationTime);
+      ((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);
+        }
+      GNUNET_GE_ASSERT (ectx,
+                        sizeof (GNUNET_DatastoreValue) + size +
+                        sizeof (GNUNET_EC_DBlock) < GNUNET_MAX_BUFFER_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_BULK |
+                                       GNUNET_GE_ADMIN | GNUNET_GE_USER,
+                                       "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),
+                                    &mchk.key);
+      GNUNET_EC_file_block_get_query (db, size + sizeof (GNUNET_EC_DBlock),
+                                      &mchk.query);
+#if DEBUG_UPLOAD
+      GNUNET_hash_to_enc (&mchk.query, &enc);
+      fprintf (stderr,
+               "Query for current block of size %u is `%s'\n", size,
+               (const char *) &enc);
+#endif
+      if (doIndex == GNUNET_YES)
+        {
+          if (GNUNET_SYSERR == GNUNET_FS_index (sock, &fileId, dblock, pos))
+            {
+              GNUNET_GE_LOG (ectx,
+                             GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                             GNUNET_GE_USER,
+                             _
+                             ("Indexing data of file `%s' failed at position 
%llu.\n"),
+                             filename, pos);
+              goto FAILURE;
+            }
+        }
+      else
+        {
+          value = NULL;
+          if (GNUNET_OK !=
+              GNUNET_EC_file_block_encode (db,
+                                           size + sizeof (GNUNET_EC_DBlock),
+                                           &mchk.query, &value))
+            {
+              GNUNET_GE_BREAK (ectx, 0);
+              goto FAILURE;
+            }
+          GNUNET_GE_ASSERT (ectx, value != NULL);
+          *value = *dblock;     /* copy options! */
+          if ((doIndex == GNUNET_NO) &&
+              (GNUNET_OK != (ret = GNUNET_FS_insert (sock, value))))
+            {
+              GNUNET_GE_BREAK (ectx, ret == GNUNET_NO);
+              GNUNET_free (value);
+              goto FAILURE;
+            }
+          GNUNET_free (value);
+        }
+      pos += size;
+      now = GNUNET_get_time ();
+      if (pos > 0)
+        {
+          eta = (GNUNET_CronTime) (start +
+                                   (((double) (now - start) / (double) pos))
+                                   * (double) filesize);
+        }
+      if (GNUNET_OK != pushBlock (sock, &mchk, 0,       /* dblocks are on 
level 0 */
+                                  iblocks, priority, expirationTime))
+        goto FAILURE;
+    }
+  if (tt != NULL)
+    if (GNUNET_OK != tt (ttClosure))
+      goto FAILURE;
+#if DEBUG_UPLOAD
+  GNUNET_GE_LOG (ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "Tree depth is %u, walking up tree.\n", treedepth);
+#endif
+  for (i = 0; i < treedepth; i++)
+    {
+      size = ntohl (iblocks[i]->size) - sizeof (GNUNET_DatastoreValue);
+      GNUNET_GE_ASSERT (ectx, size < GNUNET_MAX_BUFFER_SIZE);
+      if (size == sizeof (GNUNET_EC_DBlock))
+        {
+#if DEBUG_UPLOAD
+          GNUNET_GE_LOG (ectx,
+                         GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                         "Level %u is empty\n", i);
+#endif
+          continue;
+        }
+      db = (GNUNET_EC_DBlock *) & iblocks[i][1];
+      GNUNET_EC_file_block_get_key (db, size, &mchk.key);
+#if DEBUG_UPLOAD
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                     "Computing query for %u bytes content.\n", size);
+#endif
+      GNUNET_EC_file_block_get_query (db, size, &mchk.query);
+#if DEBUG_UPLOAD
+      IF_GELOG (ectx,
+                GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                GNUNET_hash_to_enc (&mchk.query, &enc));
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                     "Query for current block at level %u is `%s'.\n", i,
+                     &enc);
+#endif
+      if (GNUNET_OK != pushBlock (sock,
+                                  &mchk, i + 1, iblocks, priority,
+                                  expirationTime))
+        {
+          GNUNET_GE_BREAK (ectx, 0);
+          goto FAILURE;
+        }
+      GNUNET_EC_file_block_encode (db, size, &mchk.query, &value);
+      if (value == NULL)
+        {
+          GNUNET_GE_BREAK (ectx, 0);
+          goto FAILURE;
+        }
+      value->expiration_time = GNUNET_htonll (expirationTime);
+      value->priority = htonl (priority);
+      if ((doIndex != GNUNET_SYSERR) &&
+          (GNUNET_SYSERR == GNUNET_FS_insert (sock, value)))
+        {
+          GNUNET_GE_BREAK (ectx, 0);
+          GNUNET_free (value);
+          goto FAILURE;
+        }
+      GNUNET_free (value);
+      GNUNET_free (iblocks[i]);
+      iblocks[i] = NULL;
+    }
+#if DEBUG_UPLOAD
+  IF_GELOG (ectx,
+            GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+            GNUNET_hash_to_enc (&mchk.query, &enc));
+  GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "Query for top block is %s\n", &enc);
+#endif
+  /* build URI */
+  fid.file_length = GNUNET_htonll (filesize);
+  db = (GNUNET_EC_DBlock *) & iblocks[treedepth][1];
+
+  fid.chk = *(GNUNET_EC_ContentHashKey *) & (db[1]);
+  *uri = GNUNET_malloc (sizeof (URI));
+  (*uri)->type = chk;
+  (*uri)->data.fi = fid;
+
+  /* free resources */
+  GNUNET_free_non_null (iblocks[treedepth]);
+  GNUNET_free (iblocks);
+  GNUNET_free (dblock);
+  if (upcb != NULL)
+    upcb (filesize, filesize, eta, upcbClosure);
+  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;
+}
+
+#endif 
+
+/* end of fs_publish.c */

Added: gnunet/src/fs/fs_search.c
===================================================================
--- gnunet/src/fs/fs_search.c                           (rev 0)
+++ gnunet/src/fs/fs_search.c   2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,572 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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/search.c
+ * @brief Helper functions for searching.
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_fs_lib.h"
+#include "gnunet_ecrs_lib.h"
+#include "ecrs_core.h"
+#include "ecrs.h"
+
+#define DEBUG_SEARCH GNUNET_NO
+
+/**
+ * Context for an individual search.  Followed
+ *  by keyCount keys of type GNUNET_HashCode.
+ */
+struct PendingSearch
+{
+  struct PendingSearch *next;
+
+  struct GNUNET_ECRS_SearchContext *context;
+
+  /**
+   * The key (for decryption)
+   */
+  GNUNET_HashCode decryptKey;
+
+  unsigned int keyCount;
+
+  /**
+   * What type of query is it?
+   */
+  unsigned int type;
+
+};
+
+/**
+ * Context for search operation.
+ */
+struct GNUNET_ECRS_SearchContext
+{
+  /**
+   * Time when the cron-job was first started.
+   */
+  GNUNET_CronTime start;
+
+  /**
+   * What is the global timeout?
+   */
+  GNUNET_CronTime timeout;
+
+  /**
+   * Search context
+   */
+  struct GNUNET_FS_SearchContext *sctx;
+
+  /**
+   * Active searches.
+   */
+  struct PendingSearch *queries;
+
+  GNUNET_ECRS_SearchResultProcessor spcb;
+
+  void *spcbClosure;
+
+  struct GNUNET_GE_Context *ectx;
+
+  struct GNUNET_GC_Configuration *cfg;
+
+  int aborted;
+
+  int my_sctx;
+
+  unsigned int anonymityLevel;
+
+};
+
+static int
+receive_response_callback (const GNUNET_HashCode * key,
+                           const GNUNET_DatastoreValue * value,
+                           void *cls, unsigned long long uid);
+
+/**
+ * Add a query to the SQC.
+ */
+static void
+add_search (unsigned int type,
+            unsigned int keyCount,
+            const GNUNET_HashCode * keys,
+            const GNUNET_HashCode * dkey,
+            struct GNUNET_ECRS_SearchContext *sqc)
+{
+  struct PendingSearch *ps;
+
+  ps =
+    GNUNET_malloc (sizeof (struct PendingSearch) +
+                   sizeof (GNUNET_HashCode) * keyCount);
+  ps->type = type;
+  ps->keyCount = keyCount;
+  memcpy (&ps[1], keys, sizeof (GNUNET_HashCode) * keyCount);
+  ps->decryptKey = *dkey;
+  ps->context = sqc;
+  ps->next = sqc->queries;
+  sqc->queries = ps;
+  GNUNET_FS_start_search (sqc->sctx,
+                          NULL,
+                          type,
+                          keyCount,
+                          keys,
+                          sqc->anonymityLevel,
+                          &receive_response_callback, ps);
+}
+
+/**
+ * Add the query that corresponds to the given URI
+ * to the SQC.
+ */
+static void
+add_search_for_uri (const struct GNUNET_ECRS_URI *uri,
+                    struct GNUNET_ECRS_SearchContext *sqc)
+{
+  struct GNUNET_GE_Context *ectx = sqc->ectx;
+
+  switch (uri->type)
+    {
+    case chk:
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("CHK URI not allowed for search.\n"));
+      break;
+    case sks:
+      {
+        GNUNET_HashCode keys[2];
+        GNUNET_HashCode hk;     /* hk = GNUNET_hash(identifier) */
+        GNUNET_HashCode hk2;    /* hk2 = GNUNET_hash(hk) */
+
+        GNUNET_hash (uri->data.sks.identifier,
+                     strlen (uri->data.sks.identifier), &hk);
+        GNUNET_hash (&hk, sizeof (GNUNET_HashCode), &hk2);
+        /* compute routing key keys[0] = H(key) ^ namespace */
+        GNUNET_hash_xor (&hk2, &uri->data.sks.namespace, &keys[0]);
+        keys[1] = uri->data.sks.namespace;
+        add_search (GNUNET_ECRS_BLOCKTYPE_SIGNED, 2, &keys[0], &hk, sqc);
+        break;
+      }
+    case ksk:
+      {
+        GNUNET_HashCode hc;
+        GNUNET_HashCode query;
+        struct GNUNET_RSA_PrivateKey *pk;
+        GNUNET_RSA_PublicKey pub;
+        int i;
+        const char *keyword;
+
+#if DEBUG_SEARCH
+        GNUNET_GE_LOG (ectx,
+                       GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                       "Computing queries (this may take a while).\n");
+#endif
+        for (i = 0; i < uri->data.ksk.keywordCount; i++)
+          {
+            keyword = uri->data.ksk.keywords[i];
+            /* first character of the keyword is
+               "+" or " " to indicate mandatory or
+               not -- ignore for hashing! */
+            GNUNET_hash (&keyword[1], strlen (&keyword[1]), &hc);
+            pk = GNUNET_RSA_create_key_from_hash (&hc);
+            GNUNET_RSA_get_public_key (pk, &pub);
+            GNUNET_hash (&pub, sizeof (GNUNET_RSA_PublicKey), &query);
+            add_search (GNUNET_ECRS_BLOCKTYPE_ANY,      /* 
GNUNET_ECRS_BLOCKTYPE_KEYWORD, GNUNET_ECRS_BLOCKTYPE_NAMESPACE or 
GNUNET_ECRS_BLOCKTYPE_KEYWORD_FOR_NAMESPACE ok */
+                        1, &query, &hc, sqc);
+            GNUNET_RSA_free_key (pk);
+          }
+#if DEBUG_SEARCH
+        GNUNET_GE_LOG (ectx,
+                       GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                       "Queries ready.\n");
+#endif
+        break;
+      }
+    case loc:
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
+                     _("LOC URI not allowed for search.\n"));
+      break;
+    default:
+      GNUNET_GE_BREAK (ectx, 0);
+      /* unknown URI type */
+      break;
+    }
+}
+
+/**
+ * We found an GNUNET_EC_SBlock.  Decode the meta-data and call
+ * the callback of the SQC with the root-URI for the namespace,
+ * together with the namespace advertisement.  Also, if this is
+ * a result with updates, automatically start the search for
+ * updates.
+ */
+static int
+process_sblock_result (const GNUNET_EC_SBlock * sb,
+                       const GNUNET_HashCode * key,
+                       unsigned int size,
+                       struct GNUNET_ECRS_SearchContext *sqc)
+{
+  static GNUNET_HashCode allZeros;
+  struct GNUNET_GE_Context *ectx = sqc->ectx;
+  GNUNET_ECRS_FileInfo fi;
+  URI updateURI;
+  int ret;
+  const char *id;
+  const char *uris;
+  unsigned int len;
+  unsigned int off;
+  int isRoot;
+
+  len = size - sizeof (GNUNET_EC_SBlock);
+  off = GNUNET_string_buffer_tokenize ((const char *) &sb[1],
+                                       len, 2, &id, &uris);
+  if (off == 0)
+    {
+      GNUNET_GE_BREAK_OP (ectx, 0);     /* sblock malformed */
+      return GNUNET_SYSERR;
+    }
+  fi.meta = GNUNET_meta_data_deserialize (ectx, &id[off], len - off);
+  if (fi.meta == NULL)
+    {
+      GNUNET_GE_BREAK_OP (ectx, 0);     /* sblock malformed */
+      return GNUNET_SYSERR;
+    }
+  isRoot = 0 == memcmp (&sb->identifier, &allZeros, sizeof (GNUNET_HashCode));
+  fi.uri = GNUNET_ECRS_string_to_uri (ectx, uris);
+  if ((isRoot) && (fi.uri == NULL))
+    {
+      fi.uri = GNUNET_malloc (sizeof (URI));
+      fi.uri->type = sks;
+      GNUNET_hash (&sb->subspace,
+                   sizeof (GNUNET_RSA_PublicKey),
+                   &fi.uri->data.sks.namespace);
+      fi.uri->data.sks.identifier = GNUNET_strdup (id);
+    }
+  if (fi.uri == NULL)
+    {
+      GNUNET_GE_BREAK_OP (ectx, 0);     /* sblock malformed */
+      GNUNET_meta_data_destroy (fi.meta);
+      return GNUNET_SYSERR;
+    }
+  if (sqc->spcb != NULL)
+    {
+      ret = sqc->spcb (&fi, key, isRoot, sqc->spcbClosure);
+      if (ret == GNUNET_SYSERR)
+        sqc->aborted = GNUNET_YES;
+    }
+  else
+    ret = GNUNET_OK;
+  if ((strlen (id) > 0) && (strlen (uris) > 0))
+    {
+      updateURI.type = sks;
+      GNUNET_hash (&sb->subspace,
+                   sizeof (GNUNET_RSA_PublicKey),
+                   &updateURI.data.sks.namespace);
+      updateURI.data.sks.identifier = GNUNET_strdup (id);
+      add_search_for_uri (&updateURI, sqc);
+      GNUNET_free (updateURI.data.sks.identifier);
+    }
+  GNUNET_meta_data_destroy (fi.meta);
+  GNUNET_ECRS_uri_destroy (fi.uri);
+  return ret;
+}
+
+/**
+ * Process replies received in response to our
+ * queries.  Verifies, decrypts and passes valid
+ * replies to the callback.
+ *
+ * @return GNUNET_SYSERR if the entry is malformed
+ */
+static int
+receive_response_callback (const GNUNET_HashCode * key,
+                           const GNUNET_DatastoreValue * value,
+                           void *cls, unsigned long long uid)
+{
+  struct PendingSearch *ps = cls;
+  struct GNUNET_ECRS_SearchContext *sqc = ps->context;
+  struct GNUNET_GE_Context *ectx = sqc->ectx;
+  unsigned int type;
+  GNUNET_ECRS_FileInfo fi;
+  unsigned int size;
+  int ret;
+  GNUNET_HashCode query;
+  GNUNET_CronTime expiration;
+
+  expiration = GNUNET_ntohll (value->expiration_time);
+  if (expiration < GNUNET_get_time ())
+    return GNUNET_OK;           /* expired, ignore! */
+  type = ntohl (value->type);
+  size = ntohl (value->size) - sizeof (GNUNET_DatastoreValue);
+#if DEBUG_SEARCH
+  GNUNET_GE_LOG (ectx,
+                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
+                 "Search received reply of type %u and size %u.\n", type,
+                 size);
+#endif
+  if (GNUNET_OK !=
+      GNUNET_EC_file_block_check_and_get_query (size,
+                                                (const GNUNET_EC_DBlock *)
+                                                &value[1], GNUNET_YES,
+                                                &query))
+    {
+      GNUNET_GE_BREAK_OP (NULL, 0);
+      return GNUNET_SYSERR;
+    }
+  if (!((0 == memcmp (&query,
+                      (GNUNET_HashCode *) & ps[1], sizeof (GNUNET_HashCode)))
+        && ((ps->type == type) || (ps->type == GNUNET_ECRS_BLOCKTYPE_ANY))
+        && (GNUNET_YES ==
+            GNUNET_EC_is_block_applicable_for_query (type, size,
+                                                     (const GNUNET_EC_DBlock
+                                                      *) &value[1], &query,
+                                                     ps->keyCount,
+                                                     (GNUNET_HashCode *) &
+                                                     ps[1]))))
+    {
+      return GNUNET_OK;         /* not a match */
+    }
+
+  switch (type)
+    {
+    case GNUNET_ECRS_BLOCKTYPE_KEYWORD:
+      {
+        GNUNET_EC_KBlock *kb;
+        const char *dstURI;
+#if DEBUG_SEARCH
+        GNUNET_EncName enc;
+#endif
+        int j;
+
+        if (size < sizeof (GNUNET_EC_KBlock))
+          {
+            GNUNET_GE_BREAK_OP (NULL, 0);
+            return GNUNET_SYSERR;
+          }
+        kb = GNUNET_malloc (size);
+        memcpy (kb, &value[1], size);
+#if DEBUG_SEARCH
+        IF_GELOG (ectx,
+                  GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                  GNUNET_GE_USER, GNUNET_hash_to_enc (&ps->decryptKey, &enc));
+        GNUNET_GE_LOG (ectx,
+                       GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
+                       GNUNET_GE_USER,
+                       "Decrypting KBlock with key %s.\n", &enc);
+#endif
+        GNUNET_ECRS_decryptInPlace (&ps->decryptKey,
+                                    &kb[1], size - sizeof (GNUNET_EC_KBlock));
+        j = sizeof (GNUNET_EC_KBlock);
+        while ((j < size) && (((const char *) kb)[j] != '\0'))
+          j++;
+        if (j == size)
+          {
+            GNUNET_GE_BREAK_OP (ectx, 0);       /* kblock malformed */
+            GNUNET_free (kb);
+            return GNUNET_SYSERR;
+          }
+        dstURI = (const char *) &kb[1];
+        j++;
+        fi.meta = GNUNET_meta_data_deserialize (ectx,
+                                                &((const char *)
+                                                  kb)[j], size - j);
+        if (fi.meta == NULL)
+          {
+            GNUNET_GE_BREAK_OP (ectx, 0);       /* kblock malformed */
+            GNUNET_free (kb);
+            return GNUNET_SYSERR;
+          }
+        fi.uri = GNUNET_ECRS_string_to_uri (ectx, dstURI);
+        if (fi.uri == NULL)
+          {
+            GNUNET_GE_BREAK_OP (ectx, 0);       /* kblock malformed */
+            GNUNET_meta_data_destroy (fi.meta);
+            GNUNET_free (kb);
+            return GNUNET_SYSERR;
+          }
+        if (sqc->spcb != NULL)
+          {
+            ret = sqc->spcb (&fi,
+                             &ps->decryptKey, GNUNET_NO, sqc->spcbClosure);
+            if (ret == GNUNET_SYSERR)
+              sqc->aborted = GNUNET_YES;
+          }
+        else
+          ret = GNUNET_OK;
+        GNUNET_ECRS_uri_destroy (fi.uri);
+        GNUNET_meta_data_destroy (fi.meta);
+        GNUNET_free (kb);
+        return ret;
+      }
+    case GNUNET_ECRS_BLOCKTYPE_SIGNED:
+      {
+        GNUNET_EC_SBlock *sb;
+        int ret;
+
+        if (size < sizeof (GNUNET_EC_SBlock))
+          {
+            GNUNET_GE_BREAK_OP (ectx, 0);       /* sblock malformed */
+            return GNUNET_SYSERR;
+          }
+        sb = GNUNET_malloc (size);
+        memcpy (sb, &value[1], size);
+        GNUNET_ECRS_decryptInPlace (&ps->decryptKey,
+                                    &sb[1], size - sizeof (GNUNET_EC_SBlock));
+        ret = process_sblock_result (sb, &ps->decryptKey, size, sqc);
+        GNUNET_free (sb);
+        return ret;
+      }
+    case GNUNET_ECRS_BLOCKTYPE_KEYWORD_SIGNED:
+      {
+        GNUNET_EC_KSBlock *kb;
+        int ret;
+
+        if (size < sizeof (GNUNET_EC_KSBlock))
+          {
+            GNUNET_GE_BREAK_OP (ectx, 0);       /* ksblock malformed */
+            return GNUNET_SYSERR;
+          }
+        kb = GNUNET_malloc (size);
+        memcpy (kb, &value[1], size);
+        GNUNET_ECRS_decryptInPlace (&ps->decryptKey,
+                                    &kb->sblock,
+                                    size - sizeof (GNUNET_EC_KBlock) -
+                                    sizeof (unsigned int));
+        ret =
+          process_sblock_result (&kb->sblock, &ps->decryptKey,
+                                 size - sizeof (GNUNET_EC_KSBlock) +
+                                 sizeof (GNUNET_EC_SBlock), sqc);
+        GNUNET_free (kb);
+        return ret;
+      }
+    default:
+      GNUNET_GE_BREAK_OP (ectx, 0);
+      break;
+    }                           /* end switch */
+  return GNUNET_OK;
+}
+
+/**
+ * Start search for content.
+ *
+ * @param uri specifies the search parameters
+ * @param uri set to the URI of the uploaded file
+ */
+struct GNUNET_ECRS_SearchContext *
+GNUNET_ECRS_search_start (struct GNUNET_GE_Context *ectx,
+                          struct GNUNET_GC_Configuration *cfg,
+                          struct GNUNET_FS_SearchContext *sc,
+                          const struct GNUNET_ECRS_URI *uri,
+                          unsigned int anonymityLevel,
+                          GNUNET_ECRS_SearchResultProcessor spcb,
+                          void *spcbClosure)
+{
+  struct GNUNET_ECRS_SearchContext *ctx;
+
+  if (GNUNET_YES == GNUNET_ECRS_uri_test_ksk (uri))
+    {
+      if (1 != GNUNET_ECRS_uri_get_keyword_count_from_ksk (uri))
+        return NULL;
+    }
+  else
+    {
+      if (GNUNET_YES != GNUNET_ECRS_uri_test_sks (uri))
+        return NULL;
+    }
+  ctx = GNUNET_malloc (sizeof (struct GNUNET_ECRS_SearchContext));
+  ctx->start = GNUNET_get_time ();
+  ctx->anonymityLevel = anonymityLevel;
+  ctx->ectx = ectx;
+  ctx->cfg = cfg;
+  ctx->queries = NULL;
+  ctx->spcb = spcb;
+  ctx->spcbClosure = spcbClosure;
+  ctx->aborted = GNUNET_NO;
+  ctx->sctx = sc == NULL ? GNUNET_FS_create_search_context (ectx, cfg) : sc;
+  if (ctx->sctx == NULL)
+    {
+      GNUNET_free (ctx);
+      return NULL;
+    }
+  ctx->my_sctx = (sc == NULL);
+  add_search_for_uri (uri, ctx);
+  return ctx;
+}
+
+/**
+ * Stop search for content.
+ *
+ * @param uri specifies the search parameters
+ * @param uri set to the URI of the uploaded file
+ */
+void
+GNUNET_ECRS_search_stop (struct GNUNET_ECRS_SearchContext *ctx)
+{
+  struct PendingSearch *pos;
+
+  while (ctx->queries != NULL)
+    {
+      pos = ctx->queries;
+      ctx->queries = pos->next;
+      if (!ctx->my_sctx)
+        GNUNET_FS_stop_search (ctx->sctx, &receive_response_callback, pos);
+      GNUNET_free (pos);
+    }
+  if (ctx->my_sctx)
+    GNUNET_FS_destroy_search_context (ctx->sctx);
+  GNUNET_free (ctx);
+}
+
+/**
+ * Search for content.
+ *
+ * @param timeout how long to wait (relative)
+ * @param uri specifies the search parameters
+ * @param uri set to the URI of the uploaded file
+ */
+int
+GNUNET_ECRS_search (struct GNUNET_GE_Context *ectx,
+                    struct GNUNET_GC_Configuration *cfg,
+                    const struct GNUNET_ECRS_URI *uri,
+                    unsigned int anonymityLevel,
+                    GNUNET_ECRS_SearchResultProcessor spcb,
+                    void *spcbClosure, GNUNET_ECRS_TestTerminate tt,
+                    void *ttClosure)
+{
+  struct GNUNET_ECRS_SearchContext *ctx;
+
+  ctx =
+    GNUNET_ECRS_search_start (ectx, cfg, NULL,
+                              uri, anonymityLevel, spcb, spcbClosure);
+  if (ctx == NULL)
+    return GNUNET_SYSERR;
+  while (((NULL == tt) || (GNUNET_OK == tt (ttClosure)))
+         && (GNUNET_NO == GNUNET_shutdown_test ())
+         && (ctx->aborted == GNUNET_NO))
+    GNUNET_thread_sleep (100 * GNUNET_CRON_MILLISECONDS);
+  GNUNET_ECRS_search_stop (ctx);
+  return GNUNET_OK;
+}
+
+
+/* end of search.c */

Added: gnunet/src/fs/fs_test.c
===================================================================
--- gnunet/src/fs/fs_test.c                             (rev 0)
+++ gnunet/src/fs/fs_test.c     2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,259 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 2006, 2008 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/fsui/basic_fsui_test.c
+ * @brief testcase for fsui (upload-search-download-unindex)
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_fsui_lib.h"
+
+#define DEBUG_VERBOSE GNUNET_NO
+
+#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(NULL, 0); goto 
FAILURE; }
+
+static char *
+makeName (unsigned int i)
+{
+  char *fn;
+
+  fn =
+    GNUNET_malloc (strlen ("/tmp/gnunet-basic_fsui_test/BASIC_FSUI_TEST") +
+                   14);
+  GNUNET_snprintf (fn,
+                   strlen ("/tmp/gnunet-basic_fsui_test/BASIC_FSUI_TEST") +
+                   14, "/tmp/gnunet-basic_fsui_test/BASIC_FSUI_TEST%u", i);
+  GNUNET_disk_directory_create_for_file (NULL, fn);
+  return fn;
+}
+
+static volatile enum GNUNET_FSUI_EventType lastEvent;
+
+static struct GNUNET_MetaData *search_meta;
+
+static struct GNUNET_ECRS_URI *search_uri;
+
+static struct GNUNET_FSUI_Context *ctx;
+
+static void *
+eventCallback (void *cls, const GNUNET_FSUI_Event * event)
+{
+  static char unused;
+
+  switch (event->type)
+    {
+    case GNUNET_FSUI_search_resumed:
+    case GNUNET_FSUI_download_resumed:
+    case GNUNET_FSUI_upload_resumed:
+    case GNUNET_FSUI_unindex_resumed:
+      return &unused;
+    case GNUNET_FSUI_search_result:
+#if DEBUG_VERBOSE
+      printf ("Received search result\n");
+#endif
+      search_uri =
+        GNUNET_ECRS_uri_duplicate (event->data.SearchResult.fi.uri);
+      search_meta =
+        GNUNET_meta_data_duplicate (event->data.SearchResult.fi.meta);
+      break;
+    case GNUNET_FSUI_upload_completed:
+#if DEBUG_VERBOSE
+      printf ("Upload complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_download_completed:
+#if DEBUG_VERBOSE
+      printf ("Download complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_completed:
+#if DEBUG_VERBOSE
+      printf ("Unindex complete.\n");
+#endif
+      break;
+    default:
+      break;
+    }
+  lastEvent = event->type;
+  return NULL;
+}
+
+#define START_DAEMON 1
+
+int
+main (int argc, char *argv[])
+{
+#if START_DAEMON
+  pid_t daemon;
+#endif
+  int ok;
+  struct GNUNET_ECRS_URI *uri;
+  char *filename = NULL;
+  char *keywords[] = {
+    "fsui_foo",
+    "fsui_bar",
+  };
+  char keyword[40];
+  char *fn;
+  int prog;
+  struct GNUNET_MetaData *meta;
+  struct GNUNET_ECRS_URI *kuri;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_FSUI_UploadList *upload = NULL;
+  struct GNUNET_FSUI_SearchList *search = NULL;
+  struct GNUNET_FSUI_UnindexList *unindex = NULL;
+  struct GNUNET_FSUI_DownloadList *download = NULL;
+
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_DAEMON
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  CHECK (GNUNET_OK ==
+         GNUNET_wait_for_daemon_running (NULL, cfg,
+                                         60 * GNUNET_CRON_SECONDS));
+#endif
+  GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);        /* give apps time to 
start */
+  ok = GNUNET_YES;
+
+  /* ACTUAL TEST CODE */
+  ctx = GNUNET_FSUI_start (NULL, cfg, "basic_fsui_test", 32,    /* thread pool 
size */
+                           GNUNET_NO,   /* no resume */
+                           &eventCallback, NULL);
+  CHECK (ctx != NULL);
+  filename = makeName (42);
+  GNUNET_disk_file_write (NULL,
+                          filename,
+                          "foo bar test!", strlen ("foo bar test!"), "600");
+  meta = GNUNET_meta_data_create ();
+  kuri =
+    GNUNET_ECRS_keyword_command_line_to_uri (NULL, 2,
+                                             (const char **) keywords);
+  /* upload */
+  upload = GNUNET_FSUI_upload_start (ctx, filename, 
(GNUNET_FSUI_DirectoryScanCallback) & GNUNET_disk_directory_scan, NULL, 0,  /* 
anonymity */
+                                     0, /* priority */
+                                     GNUNET_YES,
+                                     GNUNET_NO,
+                                     GNUNET_NO,
+                                     GNUNET_get_time () +
+                                     5 * GNUNET_CRON_HOURS, meta, kuri, kuri);
+  CHECK (upload != NULL);
+  GNUNET_ECRS_uri_destroy (kuri);
+  GNUNET_meta_data_destroy (meta);
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_upload_completed)
+    {
+      prog++;
+      CHECK (prog <
+             10000) GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+
+  /* search */
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], keywords[1]);
+  uri = GNUNET_ECRS_keyword_string_to_uri (NULL, keyword);
+  search = GNUNET_FSUI_search_start (ctx, 0, uri);
+  GNUNET_ECRS_uri_destroy (uri);
+  CHECK (search != NULL);
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_search_result)
+    {
+      prog++;
+      CHECK (prog < 10000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_search_abort (search);
+  GNUNET_FSUI_search_stop (search);
+
+  /* download */
+  fn = makeName (43);
+  download = GNUNET_FSUI_download_start (ctx,
+                                         0,
+                                         GNUNET_NO,
+                                         search_uri,
+                                         search_meta, fn, NULL, NULL);
+  GNUNET_free (fn);
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_download_completed)
+    {
+      prog++;
+      CHECK (prog < 10000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_download_stop (download);
+  download = NULL;
+  GNUNET_ECRS_uri_destroy (search_uri);
+  GNUNET_meta_data_destroy (search_meta);
+  /* unindex */
+  unindex = GNUNET_FSUI_unindex_start (ctx, filename);
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_unindex_completed)
+    {
+      prog++;
+      CHECK (prog < 10000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  if (lastEvent != GNUNET_FSUI_unindex_completed)
+    GNUNET_FSUI_unindex_abort (unindex);
+  GNUNET_FSUI_unindex_stop (unindex);
+
+
+  /* END OF TEST CODE */
+FAILURE:
+  if (ctx != NULL)
+    GNUNET_FSUI_stop (ctx);
+  if (filename != NULL)
+    {
+      UNLINK (filename);
+      GNUNET_free (filename);
+    }
+  if (download != NULL)
+    {
+      GNUNET_FSUI_download_abort (download);
+      GNUNET_FSUI_download_stop (download);
+    }
+  filename = makeName (43);
+  /* TODO: verify file 'filename(42)' == file 'filename(43)' */
+  UNLINK (filename);
+  GNUNET_free (filename);
+
+#if START_DAEMON
+  GNUNET_GE_ASSERT (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+#endif
+  GNUNET_GC_free (cfg);
+
+  return (ok == GNUNET_YES) ? 0 : 1;
+}
+
+/* end of basic_fsui_test.c */

Added: gnunet/src/fs/fs_unindex.c
===================================================================
--- gnunet/src/fs/fs_unindex.c                          (rev 0)
+++ gnunet/src/fs/fs_unindex.c  2009-08-22 17:57:31 UTC (rev 8841)
@@ -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 */

Modified: gnunet/src/fs/fs_uri.c
===================================================================
--- gnunet/src/fs/fs_uri.c      2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/fs_uri.c      2009-08-22 17:57:31 UTC (rev 8841)
@@ -26,10 +26,10 @@
  * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER".
  * The specific structure of "IDENTIFIER" depends on the module and
  * maybe differenciated into additional subcategories if applicable.
- * This module only deals with ecrs identifiers (MODULE = "ecrs").
+ * This module only deals with fs identifiers (MODULE = "fs").
  * <p>
  *
- * This module only parses URIs for the AFS module.  The ECRS URIs fall
+ * This module only parses URIs for the AFS module.  The FS URIs fall
  * into four categories, "chk", "sks", "ksk" and "loc".  The first three
  * categories were named in analogy (!) to Freenet, but they do NOT
  * work in exactly the same way.  They are very similar from the user's
@@ -40,7 +40,7 @@
  * <ul><li>
  *
  * First, there are URIs that identify a file.  They have the format
- * "gnunet://ecrs/chk/HEX1.HEX2.SIZE".  These URIs can be used to
+ * "gnunet://fs/chk/HEX1.HEX2.SIZE".  These URIs can be used to
  * download the file.  The description, filename, mime-type and other
  * meta-data is NOT part of the file-URI since a URI uniquely
  * identifies a resource (and the contents of the file would be the
@@ -49,7 +49,7 @@
  * </li><li>
  *
  * The second category identifies entries in a namespace.  The format
- * is "gnunet://ecrs/sks/NAMESPACE/IDENTIFIER" where the namespace
+ * is "gnunet://fs/sks/NAMESPACE/IDENTIFIER" where the namespace
  * should be given in HEX.  Applications may allow using a nickname
  * for the namespace if the nickname is not ambiguous.  The identifier
  * can be either an ASCII sequence or a HEX-encoding.  If the
@@ -59,7 +59,7 @@
  * </li> <li>
  *
  * The third category identifies ordinary searches.  The format is
- * "gnunet://ecrs/ksk/KEYWORD[+KEYWORD]*".  Using the "+" syntax
+ * "gnunet://fs/ksk/KEYWORD[+KEYWORD]*".  Using the "+" syntax
  * it is possible to encode searches with the boolean "AND" operator.
  * "+" is used since it indicates a commutative 'and' operation and
  * is unlikely to be used in a keyword by itself.
@@ -67,7 +67,7 @@
  * </li><li>
  *
  * The last category identifies a datum on a specific machine.  The
- * format is "gnunet://ecrs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME".  PEER is
+ * format is "gnunet://fs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME".  PEER is
  * the BinName of the public key of the peer storing the datum.  The
  * signature (SIG) certifies that this peer has this content.
  * HEX1, HEX2 and SIZE correspond to a 'chk' URI.
@@ -211,6 +211,7 @@
           if (1 != sscanf (&out[rpos + 1], "%2X", &hx))
             {
               GNUNET_free (out);
+             *emsg = GNUNET_strdup (_("`%' must be followed by HEX number"));
               return NULL;
             }
           rpos += 3;
@@ -265,11 +266,14 @@
   pos = strlen (GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX);
   if ( (slen <= pos) ||
        (0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX, 
-                     pos) ) ||
-       (s[slen - 1] == '+') ||
+                     pos) ) )
+    return NULL;       /* not KSK URI */
+  if ( (s[slen - 1] == '+') ||
        (s[pos] == '+') )
-    return NULL;       /* no keywords / malformed */
-  
+    {
+      *emsg = GNUNET_strdup (_("Malformed KSK URI (must not begin or end with 
`+')"));
+      return NULL;
+    }
   max = 1;
   saw_quote = 0;
   for (i = pos; i < slen; i++)
@@ -284,11 +288,17 @@
         {
           max++;
           if (s[i - 1] == '+')
-            return NULL;       /* "++" not allowed */
+           {
+             *emsg = GNUNET_strdup (_("`++' not allowed in KSK URI")); 
+             return NULL;
+           }
         }
     }
   if (saw_quote == 1)
-    return NULL;       /* quotes not balanced */
+    {
+      *emsg = GNUNET_strdup (_("Quotes not balanced in KSK URI")); 
+      return NULL;
+    }
   iret = max;
   dup = GNUNET_strdup (s);
   keywords = GNUNET_malloc (max * sizeof (char *));
@@ -304,7 +314,7 @@
         {
           keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg);
           if (NULL == keywords[max])
-            goto CLEANUP;
+           goto CLEANUP;          
           dup[i] = '\0';
         }
     }
@@ -349,14 +359,21 @@
   pos = strlen (GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX);
   if ( (slen <= pos) ||
        (0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX, 
-                     pos) ) ||
-       (slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
+                     pos) ) )
+    return NULL; /* not an SKS URI */
+  if ( (slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
        (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '/') )
-    return NULL;
+    {
+      *emsg = GNUNET_strdup (_("Malformed SKS URI"));
+      return NULL;
+    }
   memcpy (enc, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
   enc[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)-1] = '\0';
   if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (enc, &namespace))
-    return NULL;
+    {
+      *emsg = GNUNET_strdup (_("Malformed SKS URI"));
+      return NULL;
+    }
   identifier = GNUNET_strdup (&s[pos + sizeof (struct 
GNUNET_CRYPTO_HashAsciiEncoded)]);
   ret = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri));
   ret->type = sks;
@@ -389,11 +406,14 @@
   pos = strlen (GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX);
   if ( (slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
        (0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX, 
-                     pos) ) ||
-       (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
+                     pos) ) )
+    return NULL; /* not a CHK URI */
+  if ( (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
        (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != 
'.') )
-    return NULL;
-
+    {
+      *emsg = GNUNET_strdup (_("Malformed CHK URI"));
+      return NULL;
+    }
   memcpy (h1,
          &s[pos], 
          sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
@@ -410,9 +430,11 @@
       (1 != SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 
2],
                     "%llu", 
                    &fi.file_length)))
-    return NULL;
+    {
+      *emsg = GNUNET_strdup (_("Malformed CHK URI"));
+      return NULL;
+    }
   fi.file_length = GNUNET_htonll (fi.file_length);
-
   ret = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri));
   ret->type = chk;
   ret->data.chk = fi;
@@ -527,18 +549,20 @@
   struct LocUriAssembly ass;
   int ret;
   size_t slen;
-  char *addr;
 
   GNUNET_assert (s != NULL);
   slen = strlen (s);
   pos = strlen (GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX);
   if ( (slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
        (0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX, 
-                     pos) ) ||
-       (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
+                     pos) ) )
+    return NULL; /* not an SKS URI */
+  if ( (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
        (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != 
'.') )
-    return NULL;
-
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed"));
+      return NULL;
+    }
   memcpy (h1,
          &s[pos], 
          sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
@@ -555,32 +579,54 @@
       (1 != SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 
2],
                     "%llu", 
                    &ass.fi.file_length)) )
-    return NULL;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed"));
+      return NULL;
+    }
   ass.fi.file_length = GNUNET_htonll (ass.fi.file_length);
 
   npos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2;
   while ((s[npos] != '\0') && (s[npos] != '.'))
     npos++;
   if (s[npos] == '\0')
-    goto ERR;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed"));
+      goto ERR;
+    }
+  npos++;
   ret = enc2bin (&s[npos], 
                 &ass.peer,
                 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
   if (ret == -1)
-    goto ERR;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode public 
key)"));
+      goto ERR;
+    }
   npos += ret;
   if (s[npos++] != '.')
-    goto ERR;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed (could not find 
signature)"));
+      goto ERR;
+    }
   ret = enc2bin (&s[npos],
                 &sig,
                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
   if (ret == -1)
-    goto ERR;
-  npos += ret;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode 
signature)"));
+      goto ERR;
+    }
+    npos += ret;
   if (s[npos++] != '.')
-    goto ERR;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed"));
+      goto ERR;
+    }
   if (1 != SSCANF (&s[npos], "%llu", &exptime))
-    goto ERR;
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed (could not parse expiration 
time)"));
+      goto ERR;
+    }
   ass.purpose.size = htonl(sizeof(struct LocUriAssembly));
   ass.purpose.purpose = htonl(GNUNET_SIGNATURE_PURPOSE_NAMESPACE_PLACEMENT);
   et.value = exptime;
@@ -590,8 +636,10 @@
                                &ass.purpose,
                                &sig,
                                &ass.peer))
-    goto ERR;
-
+    {
+      *emsg = GNUNET_strdup (_("SKS URI malformed (signature failed 
validation)"));
+      goto ERR;
+    }
   uri = GNUNET_malloc (sizeof(struct GNUNET_FS_Uri));
   uri->type = loc;
   uri->data.loc.fi = ass.fi;
@@ -601,7 +649,6 @@
 
   return uri;
 ERR:
-  GNUNET_free_non_null (addr);
   return NULL;
 }
 
@@ -618,12 +665,20 @@
                     char **emsg)
 {
   struct GNUNET_FS_Uri *ret;
+  char *msg;
 
+  if (NULL == emsg)
+    emsg = &msg;
+  *emsg = NULL;
   if ( (NULL != (ret = uri_chk_parse (uri, emsg))) ||
        (NULL != (ret = uri_ksk_parse (uri, emsg))) ||
        (NULL != (ret = uri_sks_parse (uri, emsg))) ||
        (NULL != (ret = uri_loc_parse (uri, emsg))) )
     return ret;
+  if (NULL == *emsg)
+    *emsg = GNUNET_strdup (_("Unrecognized URI type"));
+  if (emsg == &msg)
+    GNUNET_free (msg);
   return NULL;
 }
 

Modified: gnunet/src/fs/test_fs_collection.c
===================================================================
--- gnunet/src/fs/test_fs_collection.c  2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/test_fs_collection.c  2009-08-22 17:57:31 UTC (rev 8841)
@@ -28,75 +28,87 @@
 #include "gnunet_util_lib.h"
 #include "gnunet_fs_service.h"
 
-#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_break(0); goto FAILURE; }
+static struct GNUNET_CONFIGURATION_Handle *cfg;
 
-int
-main (int argc, char *argv[])
+static void* progress_cb (void *cls,
+                         const struct GNUNET_FS_ProgressInfo *info)
 {
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  int ok;
-  struct GNUNET_ClientServerConnection *sock;
-  struct GNUNET_CONTAINER_MetaData *meta;
-  struct GNUNET_CONTAINER_MetaData *have;
+  GNUNET_break (0);
+  return NULL;
+}
+
+
+static void
+task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_FS_Namespace *have;
+  struct GNUNET_FS_Namespace *ns;
   char *emsg;
   struct GNUNET_FS_Uri *uri;
+  struct GNUNET_FS_Handle *fsh;
   struct GNUNET_CONTAINER_MetaData *md;
-  struct GNUNET_FS_Handle *fsh;
 
-  GNUNET_CRYPTO_random_disable_entropy_gathering ();
-  cfg = GNUNET_CONFIGURATION_create ();
-  if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (cfg, "check.conf"))
-    {
-      GNUNET_CONFIGURATION_destroy (cfg);
-      return -1;
-    }
-  sock = NULL;
-  meta = NULL;
-  ok = GNUNET_YES;
-  meta = GNUNET_CONTAINER_meta_data_create ();
-  GNUNET_CONTAINER_meta_data_insert (meta, EXTRACTOR_MIMETYPE, "test/foo");
-
-
-  fsh = GNUNET_FS_start (sched,
+  fsh = GNUNET_FS_start (tc->sched,
                         cfg,
                         "test-fs-collection",
                         &progress_cb,
                         NULL);
-
-  /* ACTUAL TEST CODE */
+  GNUNET_assert (NULL != fsh);
   GNUNET_FS_collection_stop (fsh);
-  CHECK (NULL == GNUNET_FS_collection_get (fsh));
-  CHECK (GNUNET_OK == GNUNET_FS_collection_start (fsh, 
-                                                 namespace));
+  GNUNET_assert (NULL == GNUNET_FS_collection_get (fsh));
+  ns = GNUNET_FS_namespace_create (fsh, "test-namespace");
+  GNUNET_assert (NULL != ns);
+  GNUNET_assert (GNUNET_OK == GNUNET_FS_collection_start (fsh, 
+                                                         ns));
+  GNUNET_FS_namespace_delete (ns, GNUNET_NO);
   have = GNUNET_FS_collection_get (fsh);
-  CHECK (NULL != have);
-  CHECK (GNUNET_CONTAINER_meta_data_test_equal (have, meta));
-  GNUNET_CONTAINER_meta_data_destroy (have);
-  md = meta;
+  GNUNET_assert (NULL != have);
+  GNUNET_FS_namespace_delete (have, GNUNET_NO);
   uri =
-    GNUNET_FS_uri_parse 
("gnunet://ecrs/chk/0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
 &emsg);
+    GNUNET_FS_uri_parse 
("gnunet://fs/chk/0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
 &emsg);
+  GNUNET_assert (NULL != uri);
+  md = GNUNET_CONTAINER_meta_data_create ();
   GNUNET_FS_collection_add (fsh, uri, md);
+  GNUNET_CONTAINER_meta_data_destroy (md);
   GNUNET_FS_uri_destroy (uri);
   GNUNET_FS_stop (fsh);
-  fsh = GNUNET_FS_start (sched, cfg,
+  fsh = GNUNET_FS_start (tc->sched,
+                        cfg,
                         "test-fs-collection",
                         &progress_cb,
                         NULL);
   have = GNUNET_FS_collection_get (fsh);
-  CHECK (NULL != have);
-  CHECK (GNUNET_CONTAINER_meta_data_test_equal (have, meta));
-  GNUNET_CONTAINER_meta_data_destroy (have);
+  GNUNET_assert (NULL != have);
+  GNUNET_FS_namespace_delete (have, GNUNET_NO);
   GNUNET_FS_collection_publish (fsh);
   GNUNET_FS_collection_stop (fsh);
-  CHECK (NULL == GNUNET_FS_collection_get (fsh));
+  GNUNET_assert (NULL == GNUNET_FS_collection_get (fsh));
   GNUNET_FS_stop (fsh);
+}
 
-  /* END OF TEST CODE */
-FAILURE:
-  if (meta != NULL)
-    GNUNET_CONTAINER_meta_data_destroy (meta);
+
+int
+main (int argc, char *argv[])
+{
+  int ok;
+
+  GNUNET_log_setup ("test_fs_collection", 
+#if VERBOSE
+                   "DEBUG",
+#else
+                   "WARNING",
+#endif
+                   NULL);
+  GNUNET_CRYPTO_random_disable_entropy_gathering ();
+  cfg = GNUNET_CONFIGURATION_create ();
+  if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (cfg, 
"test_fs_collection_data.conf"))
+    {
+      GNUNET_CONFIGURATION_destroy (cfg);
+      return -1;
+    }
+  ok = GNUNET_YES;
+  GNUNET_SCHEDULER_run (&task, &ok);
   GNUNET_CONFIGURATION_destroy (cfg);
-  
   return (ok == GNUNET_YES) ? 0 : 1;
 }
 

Added: gnunet/src/fs/test_fs_collection_data.conf
===================================================================
--- gnunet/src/fs/test_fs_collection_data.conf                          (rev 0)
+++ gnunet/src/fs/test_fs_collection_data.conf  2009-08-22 17:57:31 UTC (rev 
8841)
@@ -0,0 +1,9 @@
+[PATHS]
+SERVICEHOME = /tmp/gnunet-test-fs-uri/
+DEFAULTCONFIG = /etc/gnunetd.conf
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[TESTING]
+WEAKRANDOM = YES

Modified: gnunet/src/fs/test_fs_directory.c
===================================================================
--- gnunet/src/fs/test_fs_directory.c   2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/test_fs_directory.c   2009-08-22 17:57:31 UTC (rev 8841)
@@ -152,6 +152,13 @@
   int failureCount = 0;
   int i;
 
+  GNUNET_log_setup ("test_fs_directory", 
+#if VERBOSE
+                   "DEBUG",
+#else
+                   "WARNING",
+#endif
+                   NULL);
   for (i = 17; i < 2000; i *= 2)
     {
       fprintf (stderr, ".");

Added: gnunet/src/fs/test_fs_download.c
===================================================================
--- gnunet/src/fs/test_fs_download.c                            (rev 0)
+++ gnunet/src/fs/test_fs_download.c    2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,324 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 2006, 2008 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/fsui/download_persistence_test.c
+ * @brief testcase for fsui download persistence (upload-download)
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_fsui_lib.h"
+
+#define DEBUG_VERBOSE GNUNET_NO
+
+#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; }
+
+static volatile int suspendRestart = 0;
+
+static struct GNUNET_GE_Context *ectx;
+
+static char *
+makeName (unsigned int i)
+{
+  char *fn;
+
+  fn =
+    GNUNET_malloc (strlen
+                   ("/tmp/gnunet-fsui-download_persistence_test/FSUITEST") +
+                   14);
+  GNUNET_snprintf (fn,
+                   strlen
+                   ("/tmp/gnunet-fsui-download_persistence_test/FSUITEST") +
+                   14,
+                   "/tmp/gnunet-fsui-download_persistence_test/FSUITEST%u",
+                   i);
+  GNUNET_disk_directory_create_for_file (NULL, fn);
+  return fn;
+}
+
+static volatile enum GNUNET_FSUI_EventType lastEvent;
+static volatile enum GNUNET_FSUI_EventType waitForEvent;
+static volatile int download_done;
+static struct GNUNET_FSUI_Context *ctx;
+static struct GNUNET_ECRS_URI *upURI;
+static struct GNUNET_FSUI_DownloadList *download;
+
+static void *
+eventCallback (void *cls, const GNUNET_FSUI_Event * event)
+{
+  switch (event->type)
+    {
+    case GNUNET_FSUI_download_suspended:
+      download = NULL;
+      break;
+    case GNUNET_FSUI_download_resumed:
+#if DEBUG_VERBOSE
+      printf ("Download resuming\n");
+#endif
+      download = event->data.DownloadResumed.dc.pos;
+      break;
+    case GNUNET_FSUI_upload_progress:
+#if DEBUG_VERBOSE > 1
+      printf ("Upload is progressing (%llu/%llu)...\n",
+              event->data.UploadProgress.completed,
+              event->data.UploadProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_upload_completed:
+      upURI = GNUNET_ECRS_uri_duplicate (event->data.UploadCompleted.uri);
+#if DEBUG_VERBOSE
+      printf ("Upload complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_download_completed:
+#if DEBUG_VERBOSE
+      printf ("Download complete.\n");
+#endif
+      download_done = 1;
+      break;
+    case GNUNET_FSUI_download_progress:
+#if DEBUG_VERBOSE > 1
+      printf ("Download is progressing (%llu/%llu)...\n",
+              event->data.DownloadProgress.completed,
+              event->data.DownloadProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_unindex_progress:
+#if DEBUG_VERBOSE > 1
+      printf ("Unindex is progressing (%llu/%llu)...\n",
+              event->data.UnindexProgress.completed,
+              event->data.UnindexProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_unindex_completed:
+#if DEBUG_VERBOSE
+      printf ("Unindex complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_error:
+    case GNUNET_FSUI_upload_error:
+    case GNUNET_FSUI_download_error:
+      fprintf (stderr, "Received ERROR: %d\n", event->type);
+      GNUNET_GE_BREAK (ectx, 0);
+      break;
+    case GNUNET_FSUI_download_aborted:
+#if DEBUG_VERBOSE
+      printf ("Received download aborted event.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_suspended:
+    case GNUNET_FSUI_upload_suspended:
+#if DEBUG_VERBOSE
+      fprintf (stderr, "Received SUSPENDING: %d\n", event->type);
+#endif
+      break;
+    case GNUNET_FSUI_upload_started:
+    case GNUNET_FSUI_upload_stopped:
+    case GNUNET_FSUI_download_started:
+    case GNUNET_FSUI_download_stopped:
+    case GNUNET_FSUI_unindex_started:
+    case GNUNET_FSUI_unindex_stopped:
+      break;
+    default:
+      printf ("Unexpected event: %d\n", event->type);
+      break;
+    }
+  if (lastEvent == waitForEvent)
+    return NULL;                /* ignore all other events */
+  lastEvent = event->type;
+  return NULL;
+}
+
+#define FILESIZE (1024 * 1024 * 2)
+
+#define START_DAEMON 1
+
+int
+main (int argc, char *argv[])
+{
+#if START_DAEMON
+  pid_t daemon;
+#endif
+  int ok;
+  int i;
+  char *fn = NULL;
+  char *keywords[] = {
+    "down_foo",
+    "down_bar",
+  };
+  int prog;
+  char *buf;
+  struct GNUNET_MetaData *meta = NULL;
+  struct GNUNET_ECRS_URI *kuri = NULL;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_FSUI_UnindexList *unindex = NULL;
+  struct GNUNET_FSUI_UploadList *upload = NULL;
+
+  ok = GNUNET_YES;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_DAEMON
+  GNUNET_disk_directory_remove (NULL,
+                                "/tmp/gnunet-fsui-download_persistence_test/");
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  CHECK (GNUNET_OK ==
+         GNUNET_wait_for_daemon_running (NULL, cfg,
+                                         30 * GNUNET_CRON_SECONDS));
+  GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);        /* give apps time to 
start */
+  /* ACTUAL TEST CODE */
+#endif
+  ctx = GNUNET_FSUI_start (NULL,
+                           cfg, "fsuidownload_persistence_test", 32,
+                           GNUNET_YES, &eventCallback, NULL);
+  CHECK (ctx != NULL);
+
+  /* upload */
+  fn = makeName (42);
+  buf = GNUNET_malloc (FILESIZE);
+  for (i = 0; i < FILESIZE; i++)
+    buf[i] = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 256);
+  GNUNET_disk_file_write (ectx, fn, buf, FILESIZE, "600");
+  GNUNET_free (buf);
+  meta = GNUNET_meta_data_create ();
+  kuri =
+    GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2,
+                                             (const char **) keywords);
+  waitForEvent = GNUNET_FSUI_upload_completed;
+  upload = GNUNET_FSUI_upload_start (ctx,
+                                     fn,
+                                     (GNUNET_FSUI_DirectoryScanCallback) &
+                                     GNUNET_disk_directory_scan, NULL, 0, 0,
+                                     GNUNET_YES, GNUNET_NO, GNUNET_NO,
+                                     GNUNET_get_time () +
+                                     5 * GNUNET_CRON_HOURS, meta, kuri, kuri);
+  CHECK (upload != NULL);
+  GNUNET_ECRS_uri_destroy (kuri);
+  kuri = NULL;
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_upload_completed)
+    {
+      prog++;
+      CHECK (prog < 5000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_upload_stop (upload);
+
+  /* download */
+  waitForEvent = GNUNET_FSUI_download_completed;
+  GNUNET_free (fn);
+  fn = makeName (43);
+  download_done = 0;
+  download = GNUNET_FSUI_download_start (ctx,
+                                         0,
+                                         GNUNET_NO,
+                                         upURI, meta, fn, NULL, NULL);
+  CHECK (download != NULL);
+  GNUNET_free (fn);
+  suspendRestart = 4;
+  prog = 0;
+  while (download_done == 0)
+    {
+      prog++;
+      CHECK (prog < 1000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if ((suspendRestart > 0)
+          && (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 4) == 0))
+        {
+#if 1
+#if DEBUG_VERBOSE
+          printf ("Testing FSUI suspend-resume\n");
+#endif
+          GNUNET_FSUI_stop (ctx);       /* download possibly incomplete
+                                           at this point, thus testing resume 
*/
+          ctx = GNUNET_FSUI_start (NULL,
+                                   cfg,
+                                   "fsuidownload_persistence_test",
+                                   32, GNUNET_YES, &eventCallback, NULL);
+#if DEBUG_VERBOSE
+          printf ("Resumed...\n");
+#endif
+#endif
+          suspendRestart--;
+        }
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_download_stop (download);
+  download = NULL;
+
+  /* unindex */
+  waitForEvent = GNUNET_FSUI_unindex_completed;
+  fn = makeName (42);
+  unindex = GNUNET_FSUI_unindex_start (ctx, fn);
+  CHECK (unindex != NULL);
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_unindex_completed)
+    {
+      prog++;
+      CHECK (prog < 5000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      CHECK (lastEvent != GNUNET_FSUI_unindex_error);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  CHECK (lastEvent == GNUNET_FSUI_unindex_completed);
+  /* END OF TEST CODE */
+FAILURE:
+  if (meta != NULL)
+    GNUNET_meta_data_destroy (meta);
+  if (ctx != NULL)
+    {
+      if (unindex != NULL)
+        GNUNET_FSUI_unindex_stop (unindex);
+      if (download != NULL)
+        GNUNET_FSUI_download_stop (download);
+      GNUNET_FSUI_stop (ctx);
+    }
+  if (fn != NULL)
+    {
+      UNLINK (fn);
+      GNUNET_free (fn);
+    }
+  if (kuri != NULL)
+    GNUNET_ECRS_uri_destroy (kuri);
+  fn = makeName (43);
+  /* TODO: verify file 'fn(42)' == file 'fn(43)' */
+  UNLINK (fn);
+  GNUNET_free (fn);
+  if (upURI != NULL)
+    GNUNET_ECRS_uri_destroy (upURI);
+
+#if START_DAEMON
+  GNUNET_GE_BREAK (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+#endif
+  GNUNET_GC_free (cfg);
+  return (ok == GNUNET_YES) ? 0 : 1;
+}
+
+/* end of download_persistence_test.c */

Added: gnunet/src/fs/test_fs_download_recursive.c
===================================================================
--- gnunet/src/fs/test_fs_download_recursive.c                          (rev 0)
+++ gnunet/src/fs/test_fs_download_recursive.c  2009-08-22 17:57:31 UTC (rev 
8841)
@@ -0,0 +1,380 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 2006, 2008 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/fsui/recursive_download_test.c
+ * @brief testcase for fsui recursive upload-download
+ * @author Christian Grothoff
+ * @author Heikki Lindholm
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_fsui_lib.h"
+
+#define DEBUG_VERBOSE GNUNET_NO
+
+#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; }
+
+#define FILESIZE (1024 * 1024 * 2)
+/* depth-first directory tree d=dir f=file .=end of level*/
+#define DIRECTORY_TREE_SPEC "dddf.f.d"
+
+static struct GNUNET_GE_Context *ectx;
+
+volatile int download_done;
+
+static char *
+makeName (unsigned int i)
+{
+  char *fn;
+
+  fn =
+    GNUNET_malloc (strlen
+                   ("/tmp/gnunet-fsui-recursive_download_test/FSUITEST") +
+                   15);
+  GNUNET_snprintf (fn,
+                   strlen
+                   ("/tmp/gnunet-fsui-recursive_download_test/FSUITEST") + 15,
+                   "/tmp/gnunet-fsui-recursive_download_test/FSUITEST%u/", i);
+  return fn;
+}
+
+static int
+makeHierarchyHelper (const char *current, const char *tree, int index,
+                     int check)
+{
+  unsigned int fi, i;
+  int done;
+  char *s, *buf;
+
+  fi = 0;
+  done = 0;
+  while (!done && tree[index] != '\0')
+    {
+      s = GNUNET_malloc (strlen (current) + strlen (DIR_SEPARATOR_STR) + 14);
+      GNUNET_snprintf (s, strlen (current) + strlen (DIR_SEPARATOR_STR) + 14,
+                       "%s%s%u", current, DIR_SEPARATOR_STR, fi);
+      switch (tree[index++])
+        {
+        case 'd':
+          if (check)
+            {
+              if (GNUNET_disk_directory_test (NULL, s) == GNUNET_NO)
+                {
+                  index = -1;
+                  done = 1;
+                }
+            }
+          else
+            {
+              GNUNET_disk_directory_create (NULL, s);
+            }
+          if (!done)
+            index = makeHierarchyHelper (s, tree, index, check);
+          break;
+        case 'f':
+          if (check)
+            {
+              /* TODO: compare file contents */
+              if (GNUNET_disk_directory_test (NULL, s) != GNUNET_NO)
+                {
+                  index = -1;
+                  done = 1;
+                }
+            }
+          else
+            {
+              buf = GNUNET_malloc (FILESIZE);
+              for (i = 0; i < FILESIZE; i++)
+                buf[i] = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 256);
+              GNUNET_disk_file_write (ectx, s, buf, FILESIZE, "600");
+              GNUNET_free (buf);
+            }
+          break;
+        case '.':
+          done = 1;
+          break;
+        default:
+          break;
+        }
+      GNUNET_free (s);
+      fi++;
+    }
+  return index;
+}
+
+static char *
+makeHierarchy (unsigned int i, const char *tree)
+{
+  char *fn;
+
+  fn = makeName (i);
+  makeHierarchyHelper (fn, tree, 0, 0);
+  return fn;
+}
+
+static int
+checkHierarchy (unsigned int i, const char *tree)
+{
+  char *fn;
+  int res;
+
+  fn = makeName (i);
+  if (GNUNET_disk_directory_test (NULL, fn) != GNUNET_YES)
+    {
+      GNUNET_free (fn);
+      return GNUNET_SYSERR;
+    }
+  res = ((makeHierarchyHelper (fn, tree, 0, 1) == -1) ?
+         GNUNET_SYSERR : GNUNET_OK);
+  GNUNET_free (fn);
+  return res;
+}
+
+
+static volatile enum GNUNET_FSUI_EventType lastEvent;
+static volatile enum GNUNET_FSUI_EventType waitForEvent;
+static struct GNUNET_FSUI_Context *ctx;
+static struct GNUNET_ECRS_URI *upURI;
+static struct GNUNET_FSUI_DownloadList *download;
+
+static void *
+eventCallback (void *cls, const GNUNET_FSUI_Event * event)
+{
+  switch (event->type)
+    {
+    case GNUNET_FSUI_download_suspended:
+      download = NULL;
+      break;
+    case GNUNET_FSUI_download_resumed:
+      download = event->data.DownloadResumed.dc.pos;
+      break;
+      break;
+    case GNUNET_FSUI_upload_progress:
+#if DEBUG_VERBOSE > 1
+      printf ("Upload is progressing (%llu/%llu)...\n",
+              event->data.UploadProgress.completed,
+              event->data.UploadProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_upload_completed:
+      upURI = GNUNET_ECRS_uri_duplicate (event->data.UploadCompleted.uri);
+#if DEBUG_VERBOSE
+      printf ("Upload of `%s' complete.\n",
+              event->data.UploadCompleted.filename);
+#endif
+      break;
+    case GNUNET_FSUI_download_completed:
+#if DEBUG_VERBOSE
+      printf ("Download of `%s' complete.\n",
+              event->data.DownloadCompleted.filename);
+#endif
+      if (checkHierarchy (43, DIRECTORY_TREE_SPEC) == GNUNET_OK)
+        download_done = 1;
+#if DEBUG_VERBOSE
+      else
+        printf ("Hierarchy check not successful yet...\n");
+#endif
+      break;
+    case GNUNET_FSUI_download_progress:
+#if DEBUG_VERBOSE > 1
+      printf ("Download is progressing (%llu/%llu)...\n",
+              event->data.DownloadProgress.completed,
+              event->data.DownloadProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_unindex_progress:
+#if DEBUG_VERBOSE > 1
+      printf ("Unindex is progressing (%llu/%llu)...\n",
+              event->data.UnindexProgress.completed,
+              event->data.UnindexProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_unindex_completed:
+#if DEBUG_VERBOSE
+      printf ("Unindex complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_error:
+      fprintf (stderr, "Error unindexing: %s\n",
+               event->data.UnindexError.message);
+      break;
+    case GNUNET_FSUI_upload_error:
+      fprintf (stderr, "Error uploading: %s\n",
+               event->data.UploadError.message);
+      break;
+    case GNUNET_FSUI_download_error:
+      fprintf (stderr, "Error downloading: %s\n",
+               event->data.DownloadError.message);
+      break;
+    case GNUNET_FSUI_download_aborted:
+#if DEBUG_VERBOSE
+      printf ("Received download aborted event.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_suspended:
+    case GNUNET_FSUI_upload_suspended:
+    case GNUNET_FSUI_upload_started:
+    case GNUNET_FSUI_upload_stopped:
+    case GNUNET_FSUI_download_started:
+    case GNUNET_FSUI_download_stopped:
+    case GNUNET_FSUI_unindex_started:
+    case GNUNET_FSUI_unindex_stopped:
+      break;
+    default:
+      printf ("Unexpected event: %d\n", event->type);
+      break;
+    }
+  if (lastEvent == waitForEvent)
+    return NULL;                /* ignore all other events */
+  lastEvent = event->type;
+  return NULL;
+}
+
+
+#define START_DAEMON 1
+
+int
+main (int argc, char *argv[])
+{
+#if START_DAEMON
+  pid_t daemon;
+#endif
+  int ok;
+  char *fn = NULL;
+  char *fn43 = NULL;
+  char *keywords[] = {
+    "down_foo",
+    "down_bar",
+  };
+  int prog;
+  struct GNUNET_MetaData *meta = NULL;
+  struct GNUNET_ECRS_URI *kuri = NULL;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_FSUI_UploadList *upload = NULL;
+
+  ok = GNUNET_YES;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  fprintf(stderr,
+         "Setup...\n");
+#if START_DAEMON
+  GNUNET_disk_directory_remove (NULL,
+                                "/tmp/gnunet-fsui-recursive_download_test/");
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  CHECK (GNUNET_OK ==
+         GNUNET_wait_for_daemon_running (NULL, cfg,
+                                         30 * GNUNET_CRON_SECONDS));
+  GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);        /* give apps time to 
start */
+  /* ACTUAL TEST CODE */
+#endif
+  ctx = GNUNET_FSUI_start (NULL,
+                           cfg, "fsuirecursive_download_test", 32, GNUNET_YES,
+                           &eventCallback, NULL);
+  CHECK (ctx != NULL);
+  fn = makeHierarchy (42, DIRECTORY_TREE_SPEC);
+  meta = GNUNET_meta_data_create ();
+  kuri =
+    GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2,
+                                             (const char **) keywords);
+  fprintf(stderr,
+         "Uploading...\n");
+  waitForEvent = GNUNET_FSUI_upload_completed;
+  upload = GNUNET_FSUI_upload_start (ctx,
+                                     fn,
+                                     (GNUNET_FSUI_DirectoryScanCallback) &
+                                     GNUNET_disk_directory_scan, NULL, 0, 0,
+                                     GNUNET_YES, GNUNET_NO, GNUNET_NO,
+                                     GNUNET_get_time () +
+                                     5 * GNUNET_CRON_HOURS, meta, kuri, kuri);
+  CHECK (upload != NULL);
+  GNUNET_ECRS_uri_destroy (kuri);
+  kuri = NULL;
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_upload_completed)
+    {
+      prog++;
+      CHECK (prog < 5000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_upload_stop (upload);
+  upload = NULL;
+  CHECK (upURI != NULL);
+
+  fprintf(stderr,
+         "Downloading...\n");
+  waitForEvent = GNUNET_FSUI_download_completed;
+  fn43 = makeName (43);
+  download = GNUNET_FSUI_download_start (ctx,
+                                         0,
+                                         GNUNET_YES,
+                                         upURI, meta, fn43, NULL, NULL);
+  CHECK (download != NULL);
+  GNUNET_free (fn43);
+  fn43 = NULL;
+  prog = 0;
+  while (!download_done)
+    {
+      prog++;
+      CHECK (prog < 5000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+FAILURE:
+  fprintf(stderr,
+         "Cleanup...\n");
+  if (meta != NULL)
+    GNUNET_meta_data_destroy (meta);
+  if (ctx != NULL)
+    {
+      if (download != NULL)
+        GNUNET_FSUI_download_stop (download);
+      GNUNET_FSUI_stop (ctx);
+    }
+  if (fn != NULL)
+    {
+      GNUNET_disk_directory_remove (NULL, fn);
+      GNUNET_free (fn);
+    }
+  if (kuri != NULL)
+    GNUNET_ECRS_uri_destroy (kuri);
+  fn43 = makeName (43);
+  GNUNET_disk_directory_remove (NULL, fn43);
+  GNUNET_free (fn43);
+  if (upURI != NULL)
+    GNUNET_ECRS_uri_destroy (upURI);
+
+#if START_DAEMON
+  GNUNET_GE_BREAK (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+#endif
+  GNUNET_GC_free (cfg);
+  return (ok == GNUNET_YES) ? 0 : 1;
+}
+
+/* end of recursive_download_test.c */

Modified: gnunet/src/fs/test_fs_getopt.c
===================================================================
--- gnunet/src/fs/test_fs_getopt.c      2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/test_fs_getopt.c      2009-08-22 17:57:31 UTC (rev 8841)
@@ -28,6 +28,13 @@
 int
 main (int argc, char *argv[])
 {
+  GNUNET_log_setup ("test_fs_directory", 
+#if VERBOSE
+                   "DEBUG",
+#else
+                   "WARNING",
+#endif
+                   NULL);
   fprintf (stderr, "WARNING: testcase not yet written.\n");
   return 0;                     /* testcase passed */
 }

Added: gnunet/src/fs/test_fs_search_persistence.c
===================================================================
--- gnunet/src/fs/test_fs_search_persistence.c                          (rev 0)
+++ gnunet/src/fs/test_fs_search_persistence.c  2009-08-22 17:57:31 UTC (rev 
8841)
@@ -0,0 +1,213 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 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/fsui/search_persistence_test.c
+ * @brief testcase for fsui download persistence for search
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_fsui_lib.h"
+
+#define DEBUG_VERBOSE GNUNET_NO
+
+#define UPLOAD_PREFIX "/tmp/gnunet-fsui-search_persistence_test"
+
+#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; }
+
+static struct GNUNET_GE_Context *ectx;
+
+static struct GNUNET_FSUI_Context *ctx;
+static struct GNUNET_FSUI_SearchList *search;
+static int have_error;
+
+static void *
+eventCallback (void *cls, const GNUNET_FSUI_Event * event)
+{
+  switch (event->type)
+    {
+    case GNUNET_FSUI_search_suspended:
+      search = NULL;
+      break;
+    case GNUNET_FSUI_search_resumed:
+#if DEBUG_VERBOSE
+      printf ("Search resuming\n");
+#endif
+      search = event->data.SearchResumed.sc.pos;
+      break;
+    case GNUNET_FSUI_search_result:
+#if DEBUG_VERBOSE
+      printf ("Received search result\n");
+#endif
+      break;
+    case GNUNET_FSUI_upload_progress:
+#if DEBUG_VERBOSE
+      printf ("Upload is progressing (%llu/%llu)...\n",
+              event->data.UploadProgress.completed,
+              event->data.UploadProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_upload_completed:
+#if DEBUG_VERBOSE
+      printf ("Upload complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_progress:
+#if DEBUG_VERBOSE
+      printf ("Unindex is progressing (%llu/%llu)...\n",
+              event->data.UnindexProgress.completed,
+              event->data.UnindexProgress.total);
+#endif
+      break;
+    case GNUNET_FSUI_unindex_completed:
+#if DEBUG_VERBOSE
+      printf ("Unindex complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_error:
+    case GNUNET_FSUI_upload_error:
+    case GNUNET_FSUI_download_error:
+      fprintf (stderr, "Received ERROR: %d\n", event->type);
+      GNUNET_GE_BREAK (ectx, 0);
+      break;
+    case GNUNET_FSUI_download_aborted:
+#if DEBUG_VERBOSE
+      printf ("Received download aborted event.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_suspended:
+    case GNUNET_FSUI_upload_suspended:
+#if DEBUG_VERBOSE
+      fprintf (stderr, "Received SUSPENDING: %d\n", event->type);
+#endif
+      break;
+    case GNUNET_FSUI_upload_started:
+    case GNUNET_FSUI_upload_stopped:
+    case GNUNET_FSUI_search_started:
+    case GNUNET_FSUI_search_aborted:
+    case GNUNET_FSUI_search_stopped:
+    case GNUNET_FSUI_search_update:
+    case GNUNET_FSUI_unindex_started:
+    case GNUNET_FSUI_unindex_stopped:
+      break;
+    default:
+      printf ("Unexpected event: %d\n", event->type);
+      break;
+    }
+  return NULL;
+}
+
+#define FILESIZE (1024)
+
+#define START_DAEMON 1
+
+int
+main (int argc, char *argv[])
+{
+#if START_DAEMON
+  pid_t daemon;
+#endif
+  int ok;
+  struct GNUNET_ECRS_URI *uri = NULL;
+  char *keywords[] = {
+    "down_foo",
+    "down_bar",
+  };
+  char keyword[40];
+  int prog;
+  struct GNUNET_GC_Configuration *cfg;
+  int suspendRestart = 0;
+
+
+  ok = GNUNET_YES;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_DAEMON
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  CHECK (GNUNET_OK ==
+         GNUNET_wait_for_daemon_running (NULL, cfg,
+                                         30 * GNUNET_CRON_SECONDS));
+  GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);        /* give apps time to 
start */
+  /* ACTUAL TEST CODE */
+#endif
+  ctx = GNUNET_FSUI_start (NULL,
+                           cfg, "search_persistence_test", 32, GNUNET_YES,
+                           &eventCallback, NULL);
+  CHECK (ctx != NULL);
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], keywords[1]);
+  uri = GNUNET_ECRS_keyword_string_to_uri (ectx, keyword);
+  search = GNUNET_FSUI_search_start (ctx, 0, uri);
+  CHECK (search != NULL);
+  prog = 0;
+  suspendRestart = 10;
+  while (prog < 100)
+    {
+      prog++;
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if ((suspendRestart > 0)
+          && (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 10) == 0))
+        {
+#if 1
+#if DEBUG_VERBOSE
+          printf ("Testing FSUI suspend-resume\n");
+#endif
+          GNUNET_FSUI_stop (ctx);       /* download possibly incomplete
+                                           at this point, thus testing resume 
*/
+          CHECK (search == NULL);
+          ctx = GNUNET_FSUI_start (NULL,
+                                   cfg,
+                                   "search_persistence_test", 32, GNUNET_YES,
+                                   &eventCallback, NULL);
+#if DEBUG_VERBOSE
+          printf ("Resumed...\n");
+#endif
+#endif
+          suspendRestart--;
+        }
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_search_abort (search);
+  GNUNET_FSUI_search_stop (search);
+  search = NULL;
+  /* END OF TEST CODE */
+FAILURE:
+  if (ctx != NULL)
+    GNUNET_FSUI_stop (ctx);
+  if (uri != NULL)
+    GNUNET_ECRS_uri_destroy (uri);
+
+#if START_DAEMON
+  GNUNET_GE_BREAK (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+#endif
+  GNUNET_GC_free (cfg);
+  if (have_error)
+    ok = GNUNET_NO;
+  return (ok == GNUNET_YES) ? 0 : 1;
+}
+
+/* end of search_persistence_test.c */

Added: gnunet/src/fs/test_fs_search_ranking.c
===================================================================
--- gnunet/src/fs/test_fs_search_ranking.c                              (rev 0)
+++ gnunet/src/fs/test_fs_search_ranking.c      2009-08-22 17:57:31 UTC (rev 
8841)
@@ -0,0 +1,250 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 2006, 2008 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/fsui/search_ranking_test.c
+ * @brief testcase for search ranking (availability, etc)
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_fsui_lib.h"
+
+#define CHECK_VERBOSE GNUNET_NO
+
+#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(NULL, 0); goto 
FAILURE; }
+
+static char *
+makeName (unsigned int i)
+{
+  char *fn;
+
+  fn =
+    GNUNET_malloc (strlen ("/tmp/gnunet-fsui-searchranktest/FSUITEST") + 14);
+  GNUNET_snprintf (fn,
+                   strlen ("/tmp/gnunet-fsui-searchranktest/FSUITEST") + 14,
+                   "/tmp/gnunet-fsui-searchranktest/FSUITEST%u", i);
+  GNUNET_disk_directory_create_for_file (NULL, fn);
+  return fn;
+}
+
+static struct GNUNET_FSUI_SearchList *search;
+
+static volatile enum GNUNET_FSUI_EventType lastEvent;
+
+static volatile struct GNUNET_ECRS_URI *uri;
+
+static volatile int availability;
+
+static volatile unsigned int rank;
+
+static volatile enum GNUNET_FSUI_EventType waitForEvent;
+
+static void *
+eventCallback (void *cls, const GNUNET_FSUI_Event * event)
+{
+  static char unused;
+
+  switch (event->type)
+    {
+    case GNUNET_FSUI_search_resumed:
+      search = event->data.SearchResumed.sc.pos;
+      break;
+    case GNUNET_FSUI_search_suspended:
+      search = NULL;
+      break;
+    case GNUNET_FSUI_search_update:
+      availability = event->data.SearchUpdate.availability_rank;
+      rank = event->data.SearchUpdate.applicability_rank;
+      break;
+    case GNUNET_FSUI_search_paused:
+    case GNUNET_FSUI_search_restarted:
+      break;
+    case GNUNET_FSUI_download_resumed:
+    case GNUNET_FSUI_upload_resumed:
+    case GNUNET_FSUI_unindex_resumed:
+      return &unused;
+    case GNUNET_FSUI_search_result:
+#if CHECK_VERBOSE
+      printf ("Received search result\n");
+#endif
+      uri = GNUNET_ECRS_uri_duplicate (event->data.SearchResult.fi.uri);
+      break;
+    case GNUNET_FSUI_upload_completed:
+#if CHECK_VERBOSE
+      printf ("Upload complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_download_completed:
+#if CHECK_VERBOSE
+      printf ("Download complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_unindex_completed:
+#if CHECK_VERBOSE
+      printf ("Unindex complete.\n");
+#endif
+      break;
+    case GNUNET_FSUI_upload_error:
+      printf ("Upload error.\n");
+      break;
+    case GNUNET_FSUI_download_error:
+      printf ("Download error.\n");
+      break;
+    case GNUNET_FSUI_unindex_error:
+      printf ("Unindex error.\n");
+      break;
+    default:
+      break;
+    }
+  if (lastEvent != waitForEvent)
+    lastEvent = event->type;
+  return NULL;
+}
+
+#define START_DAEMON 1
+
+int
+main (int argc, char *argv[])
+{
+#if START_DAEMON
+  pid_t daemon;
+#endif
+  int ok;
+  char *fn = NULL;
+  char *keywords[] = {
+    "search_foo",
+    "search_bar",
+  };
+  char keyword[40];
+  int prog;
+  struct GNUNET_MetaData *meta;
+  struct GNUNET_ECRS_URI *kuri;
+  struct GNUNET_GC_Configuration *cfg;
+  struct GNUNET_FSUI_UploadList *upload;
+  struct GNUNET_ECRS_URI *luri;
+  struct GNUNET_FSUI_Context *ctx = NULL;
+
+  ok = GNUNET_YES;
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_DAEMON
+  GNUNET_disk_directory_remove (NULL, "/tmp/gnunet-fsui-searchranktest/");
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  CHECK (GNUNET_OK ==
+         GNUNET_wait_for_daemon_running (NULL, cfg,
+                                         30 * GNUNET_CRON_SECONDS));
+  GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);        /* give apps time to 
start */
+  /* ACTUAL TEST CODE */
+#endif
+  ctx = GNUNET_FSUI_start (NULL,
+                           cfg, "fsuisearchranktest", 32, GNUNET_YES,
+                           &eventCallback, NULL);
+  CHECK (ctx != NULL);
+  /* upload */
+  fn = makeName (42);
+  GNUNET_disk_file_write (NULL,
+                          fn, "foo bar test!", strlen ("foo bar test!"),
+                          "600");
+  meta = GNUNET_meta_data_create ();
+  kuri =
+    GNUNET_ECRS_keyword_command_line_to_uri (NULL, 2,
+                                             (const char **) keywords);
+  waitForEvent = GNUNET_FSUI_upload_completed;
+  upload =
+    GNUNET_FSUI_upload_start (ctx,
+                              fn,
+                              (GNUNET_FSUI_DirectoryScanCallback) &
+                              GNUNET_disk_directory_scan, NULL, 0, 0,
+                              GNUNET_YES, GNUNET_NO, GNUNET_NO,
+                              GNUNET_get_time () + 5 * GNUNET_CRON_HOURS,
+                              meta, kuri, kuri);
+  CHECK (NULL != upload);
+  GNUNET_free (fn);
+  fn = NULL;
+  GNUNET_ECRS_uri_destroy (kuri);
+  GNUNET_meta_data_destroy (meta);
+  prog = 0;
+  while (lastEvent != GNUNET_FSUI_upload_completed)
+    {
+      prog++;
+      if (prog == 10000)
+        {
+          fprintf (stderr,
+                   "Upload failed to complete -- last event: %u\n",
+                   lastEvent);
+        }
+      CHECK (prog < 10000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+      if (GNUNET_shutdown_test () == GNUNET_YES)
+        break;
+    }
+  GNUNET_FSUI_upload_stop (upload);
+
+  /* search */
+  GNUNET_snprintf (keyword, 40, "%s %s", keywords[0], keywords[1]);
+  luri = GNUNET_ECRS_keyword_string_to_uri (NULL, keyword);
+  uri = NULL;
+  search = GNUNET_FSUI_search_start (ctx, 0, luri);
+  GNUNET_ECRS_uri_destroy (luri);
+  luri = NULL;
+  CHECK (NULL != search);
+  GNUNET_FSUI_search_pause (search);
+  GNUNET_FSUI_search_restart (search);
+  while ((uri == NULL) &&
+         (availability < 3) &&
+         (rank != 2) && (GNUNET_shutdown_test () != GNUNET_YES))
+    {
+      prog++;
+      CHECK (prog < 10000);
+      GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS);
+    }
+  GNUNET_FSUI_search_abort (search);
+  GNUNET_FSUI_search_stop (search);
+  CHECK (uri != NULL);
+
+
+  /* END OF TEST CODE */
+FAILURE:
+  if (ctx != NULL)
+    GNUNET_FSUI_stop (ctx);
+  GNUNET_free_non_null (fn);
+  /* TODO: verify file 'fn(42)' == file 'fn(43)' */
+  fn = makeName (42);
+  UNLINK (fn);
+  GNUNET_free (fn);
+  fn = makeName (43);
+  UNLINK (fn);
+  GNUNET_free (fn);
+
+#if START_DAEMON
+  GNUNET_GE_ASSERT (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+#endif
+  GNUNET_GC_free (cfg);
+  return (ok == GNUNET_YES) ? 0 : 1;
+}
+
+/* end of searchtest.c */

Added: gnunet/src/fs/test_fs_start_stop.c
===================================================================
--- gnunet/src/fs/test_fs_start_stop.c                          (rev 0)
+++ gnunet/src/fs/test_fs_start_stop.c  2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,89 @@
+/*
+     This file is part of GNUnet.
+     (C) 2004, 2005, 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/fsui/fsui_start_stop_test.c
+ * @brief testcase for fsui (start-stop only)
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_fsui_lib.h"
+
+#define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(NULL, 0); goto 
FAILURE; }
+
+
+static struct GNUNET_FSUI_Context *ctx;
+
+static void *
+eventCallback (void *cls, const GNUNET_FSUI_Event * event)
+{
+  return NULL;
+}
+
+#define START_DAEMON 1
+
+int
+main (int argc, char *argv[])
+{
+#if START_DAEMON
+  pid_t daemon;
+#endif
+  int ok;
+  struct GNUNET_GC_Configuration *cfg;
+
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+#if START_DAEMON
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  CHECK (GNUNET_OK ==
+         GNUNET_wait_for_daemon_running (NULL, cfg,
+                                         60 * GNUNET_CRON_SECONDS));
+#endif
+  ok = GNUNET_YES;
+  GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);        /* give apps time to 
start */
+
+  /* ACTUAL TEST CODE */
+  ctx = GNUNET_FSUI_start (NULL, cfg, "fsui_start_stop_test", 32, GNUNET_YES,  
 /* do resume! */
+                           &eventCallback, NULL);
+  CHECK (ctx != NULL);
+  GNUNET_FSUI_stop (ctx);
+  ctx =
+    GNUNET_FSUI_start (NULL, cfg, "fsui_start_stop_test", 32, GNUNET_YES,
+                       &eventCallback, NULL);
+  CHECK (ctx != NULL);
+FAILURE:
+  if (ctx != NULL)
+    GNUNET_FSUI_stop (ctx);
+#if START_DAEMON
+  GNUNET_GE_ASSERT (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+#endif
+  GNUNET_GC_free (cfg);
+
+  return (ok == GNUNET_YES) ? 0 : 1;
+}
+
+/* end of fsui_start_stop_test.c */

Modified: gnunet/src/fs/test_fs_uri.c
===================================================================
--- gnunet/src/fs/test_fs_uri.c 2009-08-21 08:41:21 UTC (rev 8840)
+++ gnunet/src/fs/test_fs_uri.c 2009-08-22 17:57:31 UTC (rev 8841)
@@ -38,10 +38,10 @@
   struct GNUNET_FS_Uri *ret;
   char *emsg;
 
-  if (NULL != GNUNET_FS_uri_parse ("gnunet://ecrs/ksk/++", &emsg))
+  if (NULL != GNUNET_FS_uri_parse ("gnunet://fs/ksk/++", &emsg))
     ABORT ();
   GNUNET_free (emsg);
-  ret = GNUNET_FS_uri_parse ("gnunet://ecrs/ksk/foo+bar", &emsg);
+  ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/foo+bar", &emsg);
   if (ret == NULL)
     ABORT ();
   if (!GNUNET_FS_uri_test_ksk (ret))
@@ -58,7 +58,7 @@
     }
 
   uri = GNUNET_FS_uri_to_string (ret);
-  if (0 != strcmp (uri, "gnunet://ecrs/ksk/foo+bar"))
+  if (0 != strcmp (uri, "gnunet://fs/ksk/foo+bar"))
     {
       GNUNET_free (uri);
       GNUNET_FS_uri_destroy (ret);
@@ -80,7 +80,7 @@
   struct GNUNET_CONFIGURATION_Handle *cfg;
 
   baseURI =
-    GNUNET_FS_uri_parse 
("gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42",
 &emsg);
+    GNUNET_FS_uri_parse 
("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42",
 &emsg);
   GNUNET_assert (baseURI != NULL);
   cfg = GNUNET_CONFIGURATION_create ();
   if (GNUNET_OK !=
@@ -97,6 +97,7 @@
     {
       GNUNET_break (0);
       GNUNET_FS_uri_destroy (baseURI);
+      GNUNET_CONFIGURATION_destroy (cfg);
       return 1;
     }
   if (!GNUNET_FS_uri_test_loc (uri))
@@ -104,6 +105,7 @@
       GNUNET_break (0);
       GNUNET_FS_uri_destroy (uri);
       GNUNET_FS_uri_destroy (baseURI);
+      GNUNET_CONFIGURATION_destroy (cfg);
       return 1;
     }
   uri2 = GNUNET_FS_uri_loc_get_uri (uri);
@@ -113,6 +115,7 @@
       GNUNET_FS_uri_destroy (uri);
       GNUNET_FS_uri_destroy (uri2);
       GNUNET_FS_uri_destroy (baseURI);
+      GNUNET_CONFIGURATION_destroy (cfg);
       return 1;
     }
   GNUNET_FS_uri_destroy (uri2);
@@ -128,6 +131,7 @@
     {
       GNUNET_break (0);
       GNUNET_FS_uri_destroy (uri);
+      GNUNET_CONFIGURATION_destroy (cfg);
       return 1;
     }
   if (GNUNET_YES != GNUNET_FS_uri_test_equal (uri, uri2))
@@ -135,10 +139,12 @@
       GNUNET_break (0);
       GNUNET_FS_uri_destroy (uri);
       GNUNET_FS_uri_destroy (uri2);
+      GNUNET_CONFIGURATION_destroy (cfg);
       return 1;
     }
   GNUNET_FS_uri_destroy (uri2);
   GNUNET_FS_uri_destroy (uri);
+  GNUNET_CONFIGURATION_destroy (cfg);
   return 0;
 }
 
@@ -150,15 +156,18 @@
   char *emsg;
 
   if (NULL !=
-      GNUNET_FS_uri_parse 
("gnunet://ecrs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK", &emsg))
+      GNUNET_FS_uri_parse ("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK", 
&emsg))
     ABORT ();
+  GNUNET_free (emsg);
   if (NULL !=
-      GNUNET_FS_uri_parse 
("gnunet://ecrs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3V/test", &emsg))
+      GNUNET_FS_uri_parse 
("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3V/test", &emsg))
     ABORT ();
-  if (NULL != GNUNET_FS_uri_parse ("gnunet://ecrs/sks/test", &emsg))
+  GNUNET_free (emsg);
+  if (NULL != GNUNET_FS_uri_parse ("gnunet://fs/sks/test", &emsg))
     ABORT ();
+  GNUNET_free (emsg);
   ret =
-    GNUNET_FS_uri_parse 
("gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test",
 &emsg);
+    GNUNET_FS_uri_parse 
("gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test",
 &emsg);
   if (ret == NULL)
     ABORT ();
   if (GNUNET_FS_uri_test_ksk (ret))
@@ -174,7 +183,7 @@
 
   uri = GNUNET_FS_uri_to_string (ret);
   if (0 != strcmp (uri,
-                   
"gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test"))
+                   
"gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test"))
     {
       GNUNET_FS_uri_destroy (ret);
       GNUNET_free (uri);
@@ -193,19 +202,19 @@
   char *emsg;
 
   if (NULL !=
-      GNUNET_FS_uri_parse 
("gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42",
 &emsg))
+      GNUNET_FS_uri_parse 
("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42",
 &emsg))
     ABORT ();
   GNUNET_free (emsg);
   if (NULL !=
-      GNUNET_FS_uri_parse 
("gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000",
 &emsg))
+      GNUNET_FS_uri_parse 
("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000",
 &emsg))
     ABORT ();
   GNUNET_free (emsg);
   if (NULL !=
-      GNUNET_FS_uri_parse 
("gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH",
 &emsg))
+      GNUNET_FS_uri_parse 
("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH",
 &emsg))
     ABORT ();
   GNUNET_free (emsg);
   ret =
-    GNUNET_FS_uri_parse 
("gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42",
 &emsg);
+    GNUNET_FS_uri_parse 
("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42",
 &emsg);
   if (ret == NULL)
     ABORT ();
   if (GNUNET_FS_uri_test_ksk (ret))
@@ -226,7 +235,7 @@
 
   uri = GNUNET_FS_uri_to_string (ret);
   if (0 != strcmp (uri,
-                   
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42"))
+                   
"gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42"))
     {
       GNUNET_free (uri);
       GNUNET_FS_uri_destroy (ret);
@@ -243,14 +252,23 @@
   int failureCount = 0;
   int i;
 
+  GNUNET_log_setup ("test_fs_uri", 
+#if VERBOSE
+                   "DEBUG",
+#else
+                   "WARNING",
+#endif
+                   NULL);
   GNUNET_CRYPTO_random_disable_entropy_gathering ();
   failureCount += testKeyword ();
   failureCount += testLocation ();
   for (i = 0; i < 255; i++)
     {
+      /* fprintf (stderr, "."); */
       failureCount += testNamespace (i);
       failureCount += testFile (i);
     }
+  /* fprintf (stderr, "\n"); */
   if (failureCount != 0)
     return 1;
   return 0;

Added: gnunet/src/fs/test_namespace.c
===================================================================
--- gnunet/src/fs/test_namespace.c                              (rev 0)
+++ gnunet/src/fs/test_namespace.c      2009-08-22 17:57:31 UTC (rev 8841)
@@ -0,0 +1,136 @@
+/*
+     This file is part of GNUnet.
+     (C) 2005, 2006, 2008 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/namespacetest.c
+ * @brief Test for namespace.c
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_ecrs_lib.h"
+#include "ecrs.h"
+
+#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); 
return 1; }
+#define CHECK(c) { do { if (!(c)) ABORT(); } while(0); }
+
+#define CHECKNAME "gnunet-namespace-test"
+
+static struct GNUNET_GC_Configuration *cfg;
+
+static int match;
+
+static int
+spcb (const GNUNET_ECRS_FileInfo * fi,
+      const GNUNET_HashCode * key, int isRoot, void *closure)
+{
+  struct GNUNET_ECRS_URI *want = closure;
+
+  if (GNUNET_ECRS_uri_test_equal (want, fi->uri))
+    match = 1;
+  else
+    fprintf (stderr,
+             "Namespace search returned unexpected result: \nHAVE: %s\nWANT: 
%s...\n",
+             GNUNET_ECRS_uri_to_string (fi->uri),
+             GNUNET_ECRS_uri_to_string (want));
+  return GNUNET_OK;
+}
+
+static int
+tt (void *unused)
+{
+  if (match == 1)
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+static int
+testNamespace ()
+{
+  GNUNET_HashCode pid;
+  struct GNUNET_ECRS_URI *adv;
+  struct GNUNET_ECRS_URI *advURI;
+  struct GNUNET_ECRS_URI *rootURI;
+  struct GNUNET_MetaData *meta;
+
+  meta = GNUNET_meta_data_create ();
+  adv = GNUNET_ECRS_keyword_string_to_uri (NULL, "testNamespace");
+  rootURI =
+    GNUNET_ECRS_namespace_create (NULL,
+                                  cfg,
+                                  meta,
+                                  0, 0,
+                                  GNUNET_get_time () +
+                                  15 * GNUNET_CRON_MINUTES, adv, "root");
+  CHECK (NULL != rootURI);
+  GNUNET_ECRS_uri_get_namespace_from_sks (rootURI, &pid);
+  advURI = GNUNET_ECRS_namespace_add_content (NULL, cfg, &pid, 1,       /* 
anonymity */
+                                              1000,     /* priority */
+                                              5 * GNUNET_CRON_MINUTES +
+                                              GNUNET_get_time (),
+                                              "this", "next", rootURI, meta);
+  CHECK (NULL != advURI);
+  fprintf (stderr, "Starting namespace search...\n");
+  CHECK (GNUNET_OK == GNUNET_ECRS_search (NULL,
+                                          cfg,
+                                          advURI, 1, &spcb, rootURI, &tt,
+                                          NULL));
+  fprintf (stderr, "Completed namespace search...\n");
+  CHECK (GNUNET_OK == GNUNET_ECRS_namespace_delete (NULL, cfg, &pid));
+  CHECK (GNUNET_SYSERR == GNUNET_ECRS_namespace_delete (NULL, cfg, &pid));
+  GNUNET_meta_data_destroy (meta);
+  GNUNET_ECRS_uri_destroy (rootURI);
+  GNUNET_ECRS_uri_destroy (advURI);
+  CHECK (match == 1);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  pid_t daemon;
+  int failureCount = 0;
+
+  GNUNET_disable_entropy_gathering ();
+  cfg = GNUNET_GC_create ();
+  if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
+    {
+      GNUNET_GC_free (cfg);
+      return -1;
+    }
+  daemon = GNUNET_daemon_start (NULL, cfg, "peer.conf", GNUNET_NO);
+  GNUNET_GE_ASSERT (NULL, daemon > 0);
+  if (GNUNET_OK !=
+      GNUNET_wait_for_daemon_running (NULL, cfg, 60 * GNUNET_CRON_SECONDS))
+    {
+      failureCount++;
+    }
+  else
+    {
+      GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);
+      failureCount += testNamespace ();
+    }
+  GNUNET_GE_ASSERT (NULL, GNUNET_OK == GNUNET_daemon_stop (NULL, daemon));
+
+  return (failureCount == 0) ? 0 : 1;
+}
+
+/* end of namespacetest.c */

Modified: gnunet/src/include/gnunet_fs_service.h
===================================================================
--- gnunet/src/include/gnunet_fs_service.h      2009-08-21 08:41:21 UTC (rev 
8840)
+++ gnunet/src/include/gnunet_fs_service.h      2009-08-22 17:57:31 UTC (rev 
8841)
@@ -441,45 +441,45 @@
 enum GNUNET_FS_Status
 {
   /**
-   * Notification that we have started to share a file structure.
+   * Notification that we have started to publish a file structure.
    */
-  GNUNET_FS_STATUS_SHARE_START,
+  GNUNET_FS_STATUS_PUBLISH_START,
 
   /**
    * Notification that we have resumed sharing a file structure.
    */
-  GNUNET_FS_STATUS_SHARE_RESUME,
+  GNUNET_FS_STATUS_PUBLISH_RESUME,
 
   /**
    * Notification that we have suspended sharing a file structure.
    */
-  GNUNET_FS_STATUS_SHARE_SUSPEND,
+  GNUNET_FS_STATUS_PUBLISH_SUSPEND,
 
   /**
    * Notification that we are making progress sharing a file structure.
    */
-  GNUNET_FS_STATUS_SHARE_PROGRESS,
+  GNUNET_FS_STATUS_PUBLISH_PROGRESS,
 
   /**
    * Notification that an error was encountered  sharing a file structure.
    * The application will continue to receive resume/suspend events for
-   * this structure until "GNUNET_FS_share_stop" is called.
+   * this structure until "GNUNET_FS_publish_stop" is called.
    */
-  GNUNET_FS_STATUS_SHARE_ERROR,
+  GNUNET_FS_STATUS_PUBLISH_ERROR,
 
   /**
    * Notification that we completed sharing a file structure.
    * The application will continue to receive resume/suspend events for
-   * this structure until "GNUNET_FS_share_stop" is called.
+   * this structure until "GNUNET_FS_publish_stop" is called.
    */
-  GNUNET_FS_STATUS_SHARE_COMPLETED,
+  GNUNET_FS_STATUS_PUBLISH_COMPLETED,
 
   /**
    * Notification that we have stopped
    * the process of uploading a file structure; no
    * futher events will be generated for this action.
    */
-  GNUNET_FS_STATUS_SHARE_STOPPED,
+  GNUNET_FS_STATUS_PUBLISH_STOPPED,
 
   /**
    * Notification that we have started this download.
@@ -640,7 +640,7 @@
 /**
  * Handle for controlling an upload.
  */
-struct GNUNET_FS_ShareContext;
+struct GNUNET_FS_PublishContext;
 
 
 /**
@@ -662,7 +662,7 @@
 
 
 /**
- * Handle for detail information about a file that is being shared.
+ * Handle for detail information about a file that is being publishd.
  * Specifies metadata, keywords, how to get the contents of the file
  * (i.e. data-buffer in memory, filename on disk) and other options.
  */
@@ -682,17 +682,17 @@
   union {
     
     /**
-     * Values for all "GNUNET_FS_STATUS_SHARE_*" events.
+     * Values for all "GNUNET_FS_STATUS_PUBLISH_*" events.
      */
     struct {
 
       /**
        * Context for controlling the upload.
        */
-      struct GNUNET_FS_ShareContext *sc;
+      struct GNUNET_FS_PublishContext *sc;
 
       /**
-       * Information about the file that is being shared.
+       * Information about the file that is being publishd.
        */
       const struct GNUNET_FS_FileInformation *fi;
 
@@ -747,7 +747,7 @@
 
        /**
         * These values are only valid for
-        * GNUNET_FS_STATUS_SHARE_PROGRESS events.
+        * GNUNET_FS_STATUS_PUBLISH_PROGRESS events.
         */
        struct {
          
@@ -770,7 +770,7 @@
 
        /**
         * These values are only valid for
-        * GNUNET_FS_STATUS_SHARE_RESUME events.
+        * GNUNET_FS_STATUS_PUBLISH_RESUME events.
         */
        struct {
          
@@ -783,7 +783,7 @@
 
        /**
         * These values are only valid for
-        * GNUNET_FS_STATUS_SHARE_ERROR events.
+        * GNUNET_FS_STATUS_PUBLISH_ERROR events.
         */
        struct {
          
@@ -796,7 +796,7 @@
 
       } specifics;
 
-    } share;
+    } publish;
 
     
     /**
@@ -1348,7 +1348,7 @@
  *         will be passed to future callbacks in the respective
  *         field in the GNUNET_FS_ProgressInfo struct.
  */
-typedef int (*GNUNET_FS_ProgressCallback)
+typedef void* (*GNUNET_FS_ProgressCallback)
   (void *cls,
    const struct GNUNET_FS_ProgressInfo *info);
 
@@ -1388,10 +1388,10 @@
 
 
 /**
- * Function called on entries in a GNUNET_FS_FileInformation share-structure.
+ * Function called on entries in a GNUNET_FS_FileInformation publish-structure.
  *
  * @param cls closure
- * @param fi the entry in the share-structure
+ * @param fi the entry in the publish-structure
  * @param length length of the file or directory
  * @param meta metadata for the file or directory (can be modified)
  * @param uri pointer to the keywords that will be used for this entry (can be 
modified)
@@ -1415,9 +1415,9 @@
 
 
 /**
- * Create an entry for a file in a share-structure.
+ * Create an entry for a file in a publish-structure.
  *
- * @param filename name of the file or directory to share
+ * @param filename name of the file or directory to publish
  * @param meta metadata for the file
  * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
  *                GNUNET_SYSERR for simulation
@@ -1426,7 +1426,7 @@
  *   keep this file available?  Use 0 for maximum anonymity and
  *   minimum reliability...
  * @param expirationTime when should this content expire?
- * @return share structure entry for the file
+ * @return publish structure entry for the file
  */
 struct GNUNET_FS_FileInformation *
 GNUNET_FS_file_information_create_from_file (void *client_info,
@@ -1439,7 +1439,7 @@
 
 
 /**
- * Create an entry for a file in a share-structure.
+ * Create an entry for a file in a publish-structure.
  *
  * @param length length of the file
  * @param data data for the file (should not be used afterwards by
@@ -1452,7 +1452,7 @@
  *   keep this file available?  Use 0 for maximum anonymity and
  *   minimum reliability...
  * @param expirationTime when should this content expire?
- * @return share structure entry for the file
+ * @return publish structure entry for the file
  */
 struct GNUNET_FS_FileInformation *
 GNUNET_FS_file_information_create_from_data (void *client_info,
@@ -1489,7 +1489,7 @@
 
 
 /**
- * Create an entry for a file in a share-structure.
+ * Create an entry for a file in a publish-structure.
  *
  * @param length length of the file
  * @param reader function that can be used to obtain the data for the file 
@@ -1504,7 +1504,7 @@
  *   keep this file available?  Use 0 for maximum anonymity and
  *   minimum reliability...
  * @param expirationTime when should this content expire?
- * @return share structure entry for the file
+ * @return publish structure entry for the file
  */
 struct GNUNET_FS_FileInformation *
 GNUNET_FS_file_information_create_from_reader (void *client_info,
@@ -1555,7 +1555,7 @@
 /**
  * Simple, useful default implementation of a directory scanner
  * (GNUNET_FS_DirectoryScanner).  This implementation expects to get a
- * UNIX filename, will share all files in the directory except hidden
+ * UNIX filename, will publish all files in the directory except hidden
  * files (those starting with a ".").  Metadata will be extracted
  * using GNU libextractor; the specific list of plugins should be
  * specified in "cls", passing NULL will disable (!)  metadata
@@ -1578,7 +1578,7 @@
 
 
 /**
- * Create a share-structure from an existing file hierarchy, inferring
+ * Create a publish-structure from an existing file hierarchy, inferring
  * and organizing keywords and metadata as much as possible.  This
  * function primarily performs the recursive build and re-organizes
  * keywords and metadata; for automatically getting metadata
@@ -1595,7 +1595,7 @@
  *   keep this file available?  Use 0 for maximum anonymity and
  *   minimum reliability...
  * @param expirationTime when should this content expire?
- * @return share structure entry for the directory, NULL on error
+ * @return publish structure entry for the directory, NULL on error
  */
 struct GNUNET_FS_FileInformation *
 GNUNET_FS_file_information_create_from_directory (void *client_info,
@@ -1607,7 +1607,7 @@
 
 
 /**
- * Create an entry for an empty directory in a share-structure.
+ * Create an entry for an empty directory in a publish-structure.
  * This function should be used by applications for which the
  * use of "GNUNET_FS_file_information_create_from_directory"
  * is not appropriate.
@@ -1620,7 +1620,7 @@
  *   keep this file available?  Use 0 for maximum anonymity and
  *   minimum reliability...
  * @param expirationTime when should this content expire?
- * @return share structure entry for the directory , NULL on error
+ * @return publish structure entry for the directory , NULL on error
  */
 struct GNUNET_FS_FileInformation *
 GNUNET_FS_file_information_create_empty_directory (void *client_info,
@@ -1632,9 +1632,9 @@
 
 
 /**
- * Add an entry to a directory in a share-structure.  Clients
- * should never modify share structures that were passed to
- * "GNUNET_FS_share_start" already.
+ * Add an entry to a directory in a publish-structure.  Clients
+ * should never modify publish structures that were passed to
+ * "GNUNET_FS_publish_start" already.
  *
  * @param dir the directory
  * @param end the entry to add; the entry must not have been
@@ -1648,9 +1648,9 @@
 
 
 /**
- * Inspect a file or directory in a share-structure.  Clients
- * should never modify share structures that were passed to
- * "GNUNET_FS_share_start" already.  When called on a directory,
+ * Inspect a file or directory in a publish-structure.  Clients
+ * should never modify publish structures that were passed to
+ * "GNUNET_FS_publish_start" already.  When called on a directory,
  * this function will FIRST call "proc" with information about
  * the directory itself and then for each of the files in the
  * directory (but not for files in subdirectories).  When called
@@ -1668,8 +1668,8 @@
 
 
 /**
- * Destroy share-structure.  Clients should never destroy share
- * structures that were passed to "GNUNET_FS_share_start" already.
+ * Destroy publish-structure.  Clients should never destroy publish
+ * structures that were passed to "GNUNET_FS_publish_start" already.
  *
  * @param fi structure to destroy
  * @param cleaner function to call on each entry in the structure
@@ -1684,21 +1684,21 @@
 
 
 /**
- * Share a file or directory.
+ * Publish a file or directory.
  *
  * @param h handle to the file sharing subsystem
  * @param ctx initial value to use for the '*ctx'
- *        in the callback (for the GNUNET_FS_STATUS_SHARE_START event).
- * @param fi information about the file or directory structure to share
- * @param namespace namespace to share the file in, NULL for no namespace
- * @param nid identifier to use for the shared content in the namespace
+ *        in the callback (for the GNUNET_FS_STATUS_PUBLISH_START event).
+ * @param fi information about the file or directory structure to publish
+ * @param namespace namespace to publish the file in, NULL for no namespace
+ * @param nid identifier to use for the publishd content in the namespace
  *        (can be NULL, must be NULL if namespace is NULL)
  * @param nuid update-identifier that will be used for future updates 
  *        (can be NULL, must be NULL if namespace or nid is NULL)
- * @return context that can be used to control the share operation
+ * @return context that can be used to control the publish operation
  */
-struct GNUNET_FS_ShareContext *
-GNUNET_FS_share_start (struct GNUNET_FS_Handle *h,
+struct GNUNET_FS_PublishContext *
+GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h,
                       void *ctx,
                       const struct GNUNET_FS_FileInformation *fi,
                       struct GNUNET_FS_Namespace *namespace,
@@ -1708,13 +1708,13 @@
 
 /**
  * Stop an upload.  Will abort incomplete uploads (but 
- * not remove blocks that have already been shared) or
+ * not remove blocks that have already been publishd) or
  * simply clean up the state for completed uploads.
  *
  * @param sc context for the upload to stop
  */
 void 
-GNUNET_FS_share_stop (struct GNUNET_FS_ShareContext *sc);
+GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *sc);
 
 
 /**
@@ -1840,9 +1840,8 @@
  * @param h handle to the file sharing subsystem
  * @param cb function to call on each known namespace
  * @param cb_cls closure for cb
- * @return GNUNET_SYSERR on error, otherwise the number of pseudonyms in list
  */
-int 
+void 
 GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
                          GNUNET_FS_NamespaceInfoProcessor cb,
                          void *cb_cls);





reply via email to

[Prev in Thread] Current Thread [Next in Thread]