gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r3482 - in GNUnet/src: applications/fs/fsui applications/fs


From: grothoff
Subject: [GNUnet-SVN] r3482 - in GNUnet/src: applications/fs/fsui applications/fs/tools include
Date: Thu, 12 Oct 2006 20:09:50 -0700 (PDT)

Author: grothoff
Date: 2006-10-12 20:09:42 -0700 (Thu, 12 Oct 2006)
New Revision: 3482

Added:
   GNUnet/src/applications/fs/fsui/deserialize.c
   GNUnet/src/applications/fs/fsui/serialize.c
Modified:
   GNUnet/src/applications/fs/fsui/Makefile.am
   GNUnet/src/applications/fs/fsui/download.c
   GNUnet/src/applications/fs/fsui/fsui.c
   GNUnet/src/applications/fs/fsui/fsui.h
   GNUnet/src/applications/fs/fsui/search.c
   GNUnet/src/applications/fs/fsui/unindex.c
   GNUnet/src/applications/fs/fsui/upload.c
   GNUnet/src/applications/fs/tools/gnunet-download.c
   GNUnet/src/applications/fs/tools/gnunet-insert.c
   GNUnet/src/applications/fs/tools/gnunet-unindex.c
   GNUnet/src/include/gnunet_fsui_lib.h
Log:
fsui hacking

Modified: GNUnet/src/applications/fs/fsui/Makefile.am
===================================================================
--- GNUnet/src/applications/fs/fsui/Makefile.am 2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/Makefile.am 2006-10-13 03:09:42 UTC (rev 
3482)
@@ -6,9 +6,11 @@
 noinst_PROGRAMS = fsui-loader
 
 libgnunetfsui_la_SOURCES = \
+  deserialize.c \
   download.c \
   fsui.c fsui.h \
   search.c \
+  serialize.c \
   unindex.c \
   upload.c
 libgnunetfsui_la_LIBADD = \

Added: GNUnet/src/applications/fs/fsui/deserialize.c
===================================================================
--- GNUnet/src/applications/fs/fsui/deserialize.c       2006-10-12 20:51:47 UTC 
(rev 3481)
+++ GNUnet/src/applications/fs/fsui/deserialize.c       2006-10-13 03:09:42 UTC 
(rev 3482)
@@ -0,0 +1,527 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 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/deserializer.c
+ * @brief FSUI functions for reading state from disk
+ * @author Christian Grothoff
+ * @see serializer.c
+ *
+ * TODO:
+ * - deserialize upload and unindex!
+ */
+
+#include "platform.h"
+#include "gnunet_fsui_lib.h"
+#include "gnunet_directories.h"
+#include "fsui.h"
+
+
+static int read_int(int fd,
+                   int * val) {
+  int big;
+
+  if (sizeof(int) != READ(fd, &big, sizeof(int))) \
+    return SYSERR;                               \
+  *val = ntohl(big);
+  return OK;  
+}
+
+#define READINT(a) if (OK != read_int(fd, (int*) a)) return SYSERR;
+
+static int read_long(int fd,
+                    long long * val) {
+  long long big;
+
+  if (sizeof(long long) != READ(fd, &big, sizeof(long long))) \
+    return SYSERR;                               \
+  *val = ntohll(big);
+  return OK;  
+}
+
+#define READLONG(a) if (OK != read_long(fd, (long long*) a)) return SYSERR;
+
+static struct ECRS_URI * read_uri(struct GE_Context * ectx,
+                                 int fd) {
+  char * buf;
+  struct ECRS_URI * ret;
+  unsigned int size;
+
+  if (OK != read_int(fd, (int*) &size))
+    return NULL;
+  buf = MALLOC(size+1);
+  buf[size] = '\0';
+  if (size != READ(fd,
+                  buf,
+                  size)) {
+    FREE(buf);
+    return NULL;
+  }
+  ret = ECRS_stringToUri(ectx, buf);
+  FREE(buf);
+  return ret;
+}
+
+#define READURI(u) if (NULL == (u = read_uri(ectx, fd))) return SYSERR;
+
+static char * read_string(int fd,
+                         unsigned int maxLen) {
+  char * buf;
+  unsigned int big;
+
+  if (OK != read_int(fd, (int*) &big))
+    return NULL;
+  if (big > maxLen) 
+    return NULL;
+  buf = MALLOC(big + 1);
+  buf[big] = '\0';
+  if (big != READ(fd, buf, big)) {
+    FREE(buf);
+    return NULL;
+  }
+  return buf;    
+}
+
+static void fixState(FSUI_State * state) {
+  switch (*state) { /* try to correct errors */
+  case FSUI_ACTIVE:
+    *state = FSUI_PENDING;
+    break;
+  case FSUI_PENDING:
+  case FSUI_COMPLETED_JOINED:
+  case FSUI_ABORTED_JOINED:
+  case FSUI_ERROR_JOINED:
+    break;
+  case FSUI_ERROR:
+    *state = FSUI_ERROR_JOINED;
+    break;
+  case FSUI_ABORTED:
+    *state = FSUI_ABORTED_JOINED;
+    break;
+  case FSUI_COMPLETED:
+    *state = FSUI_COMPLETED_JOINED;
+    break;
+  default:
+    *state = FSUI_ERROR_JOINED;
+    break;
+  }
+}
+
+/**
+ * (Recursively) read a download list from the given fd.  The returned
+ * pointer is expected to be integrated into the tree either as a next
+ * or child pointer such that the given parent becomes the parent of the
+ * returned node.
+ *
+ * @return NULL on error AND on read of empty
+ *  list (these two cannot be distinguished)
+ */
+static FSUI_DownloadList * readDownloadList(struct GE_Context * ectx,
+                                           int fd,
+                                           FSUI_Context * ctx,
+                                           FSUI_DownloadList * parent) {
+  FSUI_DownloadList * ret;
+  unsigned int big;
+  int i;
+  int ok;
+
+  GE_ASSERT(ectx, ctx != NULL);
+  if ( (OK != read_int(fd, (int*) &big)) ||
+       (big == 0) )
+    return NULL;
+  ret = MALLOC(sizeof(FSUI_DownloadList));
+  memset(ret,
+        0,
+        sizeof(FSUI_DownloadList));
+  ret->ctx = ctx;
+  if ( (OK != read_int(fd, (int*) &ret->state)) ||
+       (OK != read_int(fd, (int*) &ret->is_recursive)) ||
+       (OK != read_int(fd, (int*) &ret->is_directory)) ||
+       (OK != read_int(fd, (int*) &ret->anonymityLevel)) ||
+       (OK != read_int(fd, (int*) &ret->completedDownloadsCount)) ||
+       (OK != read_long(fd, (long long*) &ret->total)) ||
+       (OK != read_long(fd, (long long*) &ret->completed)) ||
+       (OK != read_long(fd, (long long*) &ret->runTime)) ||
+       (OK != read_int(fd, (int*) &big)) ||
+       (big > 1024 * 1024) ) {
+    FREE(ret);
+    return NULL;
+  }
+  fixState(&ret->state);
+  ret->filename = MALLOC(big+1);
+  ret->filename[big] = '\0';
+  if (big != READ(fd, ret->filename, big)) {
+    GE_BREAK(ectx, 0);
+    FREE(ret->filename);
+    FREE(ret);
+    return NULL;
+  }
+  if (NULL == (ret->uri = read_uri(ectx, fd))) {
+    FREE(ret->filename);
+    FREE(ret);
+    return NULL;
+  }
+  if (ret->completedDownloadsCount > 0) 
+    ret->completedDownloads
+      = MALLOC(sizeof(struct ECRS_URI *) *
+              ret->completedDownloadsCount);  
+  ok = YES;
+  for (i=0;i<ret->completedDownloadsCount;i++) {
+    ret->completedDownloads[i] = read_uri(ectx, fd);
+    if (ret->completedDownloads[i] == NULL) 
+      ok = NO;    
+  }
+  if (NO == ok) {
+    FREE(ret->filename);
+    ECRS_freeUri(ret->uri);
+    for (i=0;i<ret->completedDownloadsCount;i++) {
+      if (ret->completedDownloads[i] != NULL)
+       ECRS_freeUri(ret->completedDownloads[i]);
+    }
+    FREE(ret->completedDownloads);
+    FREE(ret);
+    return NULL;
+  }
+  ret->parent = parent;
+  ret->next = readDownloadList(ectx,
+                              fd,
+                              ctx,
+                              parent);
+  ret->child = readDownloadList(ectx,
+                               fd,
+                               ctx,
+                               ret);
+#if DEBUG_PERSISTENCE
+  GE_LOG(ectx, 
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "FSUI persistence: restoring download `%s': (%llu, %llu)\n",
+        ret->filename,
+        ret->completed,
+        ret->total);
+#endif
+  return ret;
+}
+
+
+/**
+ * Read file info from file.
+ *
+ * @return OK on success, SYSERR on error
+ */
+static int readFileInfo(struct GE_Context * ectx,
+                       int fd,
+                       ECRS_FileInfo * fi) {
+  unsigned int size;
+  char * buf;
+
+  fi->meta = NULL;
+  fi->uri = NULL;
+  READINT(size);  
+  if (size > 1024 * 1024) {
+    GE_BREAK(ectx, 0);
+    return SYSERR;
+  }
+  buf = MALLOC(size);
+  if (size != READ(fd,
+                  buf,
+                  size)) {
+    FREE(buf);
+    GE_BREAK(ectx, 0);
+    return SYSERR;
+  }
+  fi->meta = ECRS_deserializeMetaData(ectx,
+                                     buf,
+                                     size);
+  if (fi->meta == NULL) {
+    FREE(buf);
+    GE_BREAK(ectx, 0);
+    return SYSERR;
+  }
+  FREE(buf);
+
+  fi->uri
+    = read_uri(ectx, fd);
+  if (fi->uri == NULL) {
+    ECRS_freeMetaData(fi->meta);
+    fi->meta = NULL;
+    GE_BREAK(ectx, 0);
+    return SYSERR;
+  }
+  return OK;
+}
+
+static int checkMagic(int fd) {
+  char magic[8];
+
+  if (8 != READ(fd, magic, 8)) {
+    GE_BREAK(NULL, 0);
+    return SYSERR;
+  }
+  if (0 != memcmp(magic,
+                 "FSUI01\n\0",
+                 8)) {
+    GE_BREAK(NULL, 0);
+    return SYSERR;
+  }
+  return OK;
+}
+
+static int readCollection(int fd,
+                         struct FSUI_Context * ctx) {
+  int big;
+
+  /* deserialize collection data */
+  READINT(big);
+  if ( (big > 16 * 1024 * 1024) ||
+       (big < sizeof(unsigned int) ) ) {
+    GE_BREAK(NULL, 0);
+    return SYSERR;
+  }
+  if (big == 0) {
+    ctx->collectionData = NULL;
+    return OK;
+  } 
+  ctx->collectionData
+    = MALLOC(big);
+  if (big - sizeof(unsigned int) !=
+      READ(fd,
+          &ctx->collectionData[1],
+          big - sizeof(unsigned int))) {
+    FREE(ctx->collectionData);
+    ctx->collectionData = NULL;
+    GE_BREAK(NULL, 0);
+    return SYSERR;
+  }
+  return OK;
+}
+
+static int readSearches(int fd,
+                       struct FSUI_Context * ctx) {
+  int big;
+  FSUI_SearchList * list;
+  int i;
+  ResultPending * rp;
+  char * buf;
+
+  while (1) {
+    READINT(big);
+    if (big == 0)
+      return OK;
+    list
+      = MALLOC(sizeof(FSUI_SearchList));       
+    memset(list,
+          0,
+          sizeof(FSUI_SearchList));
+    if ( (OK != read_int(fd, (int*) &list->state)) ||
+        (OK != read_int(fd, (int*) &list->anonymityLevel)) ||
+        (OK != read_int(fd, (int*) &list->sizeResultsReceived)) ||
+        (OK != read_int(fd, (int*) &list->sizeUnmatchedResultsReceived)) ||
+        (list->sizeResultsReceived > 1024*1024) ||     
+        (list->sizeUnmatchedResultsReceived > 1024*1024) ) {
+      GE_BREAK(NULL, 0);       
+      break;
+    }
+    fixState(&list->state);
+    buf = read_string(fd, 1024 * 1024);
+    if (buf == NULL) {
+      GE_BREAK(NULL, 0);       
+      break;
+    }
+    list->uri
+      = ECRS_stringToUri(NULL, buf);
+    FREE(buf);
+    if (list->uri == NULL) {
+      GE_BREAK(NULL, 0);       
+      break;
+    }
+    if (! ECRS_isKeywordUri(list->uri)) {
+      GE_BREAK(NULL, 0);               
+      break;
+    }
+    list->numberOfURIKeys
+      = ECRS_countKeywordsOfUri(list->uri);
+    if (list->sizeResultsReceived > 0) {
+      list->resultsReceived
+       = MALLOC(list->sizeResultsReceived *
+                sizeof(ECRS_FileInfo));
+      memset(list->resultsReceived,
+            0,
+            list->sizeResultsReceived *
+            sizeof(ECRS_FileInfo));
+    }
+    if (list->sizeUnmatchedResultsReceived > 0) {
+      list->unmatchedResultsReceived
+       = MALLOC(list->sizeUnmatchedResultsReceived *
+                sizeof(ResultPending));
+      memset(list->unmatchedResultsReceived,
+            0,
+            list->sizeUnmatchedResultsReceived *
+            sizeof(ResultPending));         
+    }
+    for (i=0;i<list->sizeResultsReceived;i++)
+      if (OK != readFileInfo(ctx->ectx,
+                            fd,
+                            &list->resultsReceived[i])) {
+       GE_BREAK(NULL, 0);
+       goto ERR;
+      }
+    for (i=0;i<list->sizeUnmatchedResultsReceived;i++) {
+      rp = &list->unmatchedResultsReceived[i];
+      if (OK != readFileInfo(ctx->ectx,
+                            fd,
+                            &rp->fi)) {
+       GE_BREAK(NULL, 0);      
+       goto ERR;
+      }
+      if (OK != read_int(fd, (int*) &rp->matchingKeyCount)) {
+       GE_BREAK(NULL, 0);      
+       goto ERR;
+      }
+      if ( (rp->matchingKeyCount > 1024) ||
+          (rp->matchingKeyCount >= list->numberOfURIKeys) ) {
+       GE_BREAK(NULL, 0);      
+       goto ERR;
+      }
+      if (rp->matchingKeyCount > 0) {
+       rp->matchingKeys
+         = MALLOC(sizeof(HashCode512) *
+                  rp->matchingKeyCount);
+       if (sizeof(HashCode512) *
+           rp->matchingKeyCount !=
+           READ(fd,
+                rp->matchingKeys,
+                sizeof(HashCode512) *
+                rp->matchingKeyCount)) {
+         GE_BREAK(NULL, 0);
+         goto ERR;
+       }
+      }
+    }  
+    list->signalTerminate
+      = NO;
+    list->ctx
+      = ctx;
+    
+    /* finally: prepend to list */
+    list->next
+      = ctx->activeSearches;
+    ctx->activeSearches
+      = list;
+  } /* end OUTER: 'while(1)' */
+ ERR:
+  /* error - deallocate 'list' */
+  for (i=0;i<list->sizeResultsReceived;i++) {
+    if (list->resultsReceived[i].uri != NULL)
+      ECRS_freeUri(list->resultsReceived[i].uri);
+    if (list->resultsReceived[i].meta != NULL)
+      ECRS_freeMetaData(list->resultsReceived[i].meta);        
+  }
+  GROW(list->resultsReceived,
+       list->sizeResultsReceived,
+       0);
+  for (i=0;i<list->sizeUnmatchedResultsReceived;i++) {
+    rp = &list->unmatchedResultsReceived[i];
+    
+    if (rp->fi.uri != NULL)
+      ECRS_freeUri(rp->fi.uri);
+    if (rp->fi.meta != NULL)
+      ECRS_freeMetaData(rp->fi.meta);
+    FREENONNULL(rp->matchingKeys);
+  }
+  GROW(list->resultsReceived,
+       list->sizeResultsReceived,
+       0);  
+  if (list->uri != NULL)
+    ECRS_freeUri(list->uri);  
+  FREE(list);
+  return SYSERR;
+}
+
+static int readDownloads(int fd,
+                        struct FSUI_Context * ctx) {
+  memset(&ctx->activeDownloads,
+        0,
+        sizeof(FSUI_DownloadList));
+  ctx->activeDownloads.child
+    = readDownloadList(ctx->ectx,
+                      fd,
+                      ctx,
+                      &ctx->activeDownloads);
+  return OK;
+}
+
+static int readUploads(int fd,
+                      struct FSUI_Context * ctx) {
+  int big;
+
+  while (1) {
+    READINT(big);
+    if (big != 1) 
+      return OK;
+
+    /* FIXME: deserialize! */
+  }
+  return SYSERR;
+}
+
+static int readUnindex(int fd,
+                      struct FSUI_Context * ctx) {
+  int big;
+
+  while (1) {
+    READINT(big);
+    if (big != 1) 
+      return OK;
+
+    /* FIXME: deserialize! */    
+  }
+  return SYSERR;
+}
+
+
+void FSUI_deserialize(struct FSUI_Context * ctx) {
+  int fd;
+
+  fd = -1;
+  if (0 != ACCESS(ctx->name, R_OK)) 
+    return;
+  fd = disk_file_open(ctx->ectx,
+                     ctx->name,
+                     O_RDONLY);  
+  if (fd == -1) 
+    return;
+
+  if ( (OK != checkMagic(fd)) ||
+       (OK != readCollection(fd, ctx) ) ||
+       (OK != readSearches(fd, ctx) ) ||
+       (OK != readDownloads(fd, ctx) ) ||
+       (OK != readUnindex(fd, ctx) ) ||
+       (OK != readUploads(fd, ctx) ) ) {
+    GE_BREAK(ctx->ectx, 0);
+    GE_LOG(ctx->ectx, 
+          GE_WARNING | GE_BULK | GE_USER,
+          _("FSUI state file `%s' had syntax error at offset %u.\n"),
+          ctx->name,
+          lseek(fd, 0, SEEK_CUR));
+  }
+  CLOSE(fd);
+  UNLINK(ctx->name);
+}


Property changes on: GNUnet/src/applications/fs/fsui/deserialize.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: GNUnet/src/applications/fs/fsui/download.c
===================================================================
--- GNUnet/src/applications/fs/fsui/download.c  2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/download.c  2006-10-13 03:09:42 UTC (rev 
3482)
@@ -25,7 +25,7 @@
  * @author Christian Grothoff
  *
  * TODO:
- * - does not signal all events properly!
+ * - can do better ETA computation (in case of suspend-resume)
  */
 
 #include "platform.h"
@@ -63,7 +63,9 @@
   if (isRoot == YES)
     return OK; /* namespace ad, ignore */
 
-  URITRACK_trackURI(ectx, parent->ctx->cfg, fi);
+  URITRACK_trackURI(ectx, 
+                   parent->ctx->cfg,
+                   fi);
   for (i=0;i<parent->completedDownloadsCount;i++)
     if (ECRS_equalsUri(parent->completedDownloads[i],
                       fi->uri))
@@ -79,7 +81,8 @@
                                  EXTRACTOR_FILENAME);
   if (filename == NULL) {
     char * tmp = ECRS_uriToString(fi->uri);
-    GE_ASSERT(ectx, strlen(tmp) >= strlen(ECRS_URI_PREFIX) + 
strlen(ECRS_FILE_INFIX));
+    GE_ASSERT(ectx, 
+             strlen(tmp) >= strlen(ECRS_URI_PREFIX) + strlen(ECRS_FILE_INFIX));
     filename = STRDUP(&tmp[strlen(ECRS_URI_PREFIX) + strlen(ECRS_FILE_INFIX)]);
     FREE(tmp);
   }
@@ -94,15 +97,18 @@
   while (NULL != (dotdot = strstr(fullName, "..")))
     dotdot[0] = dotdot[1] = '_';
   disk_directory_create(ectx, fullName);
-  strcat(fullName, DIR_SEPARATOR_STR);
+  strcat(fullName, 
+        DIR_SEPARATOR_STR);
   while (NULL != (dotdot = strstr(filename, "..")))
     dotdot[0] = dotdot[1] = '_';
-  strcat(fullName, filename);
+  strcat(fullName,
+        filename);
   FREE(filename);
 #if DEBUG_DTM
-  GE_LOG(ectx, GE_DEBUG | GE_REQUEST | GE_USER,
-      "Starting recursive download of `%s'\n",
-      fullName);
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "Starting recursive download of `%s'\n",
+        fullName);
 #endif
   startDownload(parent->ctx,
                parent->anonymityLevel,
@@ -128,19 +134,15 @@
   FSUI_DownloadList * dl = cls;
   FSUI_Event event;
   struct ECRS_MetaData * md;
-  FSUI_DownloadList * root;
 
-  root = dl;
-  while ( (root->parent != NULL) &&
-         (root->parent != &dl->ctx->activeDownloads) )
-    root = root->parent;
-
-  dl->completedFile = completedBytes;
+  GE_ASSERT(dl->ctx->ectx,
+           dl->total == totalBytes);
+  dl->completed = completedBytes;
   event.type = FSUI_download_progress;
-  event.data.DownloadProgress.total = totalBytes;
-  event.data.DownloadProgress.completed = dl->completed + completedBytes;
+  event.data.DownloadProgress.total = dl->total;
+  event.data.DownloadProgress.completed = dl->completed;
   event.data.DownloadProgress.last_offset = lastBlockOffset;
-  event.data.DownloadProgress.eta = eta;
+  event.data.DownloadProgress.eta = eta; /* FIXME: we can do better in FSUI! */
   event.data.DownloadProgress.last_block = lastBlock;
   event.data.DownloadProgress.last_size = lastBlockSize;
   event.data.DownloadProgress.filename = dl->filename;
@@ -148,7 +150,7 @@
   event.data.DownloadProgress.dc.pos = dl;
   event.data.DownloadProgress.dc.cctx = dl->cctx;
   event.data.DownloadProgress.dc.ppos = dl->parent;
-  event.data.DownloadProgress.dc.pcctx = dl->parent != NULL ? dl->parent->cctx 
: NULL;
+  event.data.DownloadProgress.dc.pcctx = dl->parent->cctx;
   dl->ctx->ecb(dl->ctx->ecbClosure,
               &event);
   if ( (lastBlockOffset == 0) &&
@@ -185,11 +187,9 @@
 testTerminate(void * cls) {
   FSUI_DownloadList * dl = cls;
 
-  if (dl->state != FSUI_DOWNLOAD_ACTIVE) {
+  if (dl->state != FSUI_ACTIVE) 
     return SYSERR;
-  } else {
-    return OK;
-  }
+  return OK;  
 }
 
 /**
@@ -199,11 +199,9 @@
   FSUI_DownloadList * dl = cls;
   int ret;
   FSUI_Event event;
-  struct ECRS_MetaData * md;
-  FSUI_DownloadList * root;
-  unsigned long long totalBytes;
   struct GE_Context * ectx;
 
+  dl->startTime = get_time() - dl->runTime;
   ectx = dl->ctx->ectx;
 #if DEBUG_DTM
   GE_LOG(ectx,
@@ -223,29 +221,29 @@
                          &testTerminate,
                          dl);  
   if (ret == OK) {
-    dl->state = FSUI_DOWNLOAD_COMPLETED;
-    totalBytes = ECRS_fileSize(dl->uri);
-  } else {
-#if DEBUG_DTM
-    GE_LOG(ectx, 
-          GE_DEBUG | GE_REQUEST | GE_USER,
-          "Download thread for `%s' failed (aborted or error)!\n",
-          dl->filename);
-#endif
-    if (dl->state == FSUI_DOWNLOAD_ACTIVE)
-      dl->state = FSUI_DOWNLOAD_ERROR;
-    else if ( (dl->state != FSUI_DOWNLOAD_ABORTED) &&
-             (dl->state != FSUI_DOWNLOAD_SUSPENDING) )
-      GE_BREAK(ectx, 0);
-    totalBytes = 0;
+    dl->state = FSUI_COMPLETED;
+    event.type = FSUI_download_complete;
+    event.data.DownloadCompleted.total = dl->total;
+    event.data.DownloadCompleted.filename = dl->filename;
+    event.data.DownloadCompleted.uri = dl->uri;
+    event.data.DownloadCompleted.dc.pos = dl;
+    event.data.DownloadCompleted.dc.cctx = dl->cctx;
+    event.data.DownloadCompleted.dc.ppos = dl->parent;
+    event.data.DownloadCompleted.dc.pcctx = dl->parent->cctx;
+    dl->ctx->ecb(dl->ctx->ecbClosure,
+                &event);
+  } else if (dl->state == FSUI_ACTIVE) {
+    /* ECRS error, we did not signal to abort */
+    dl->state = FSUI_ERROR;
+    event.type = FSUI_download_error;
+    event.data.DownloadError.message = _("ECRS download failed (see logs)");
+    event.data.DownloadError.dc.pos = dl;
+    event.data.DownloadError.dc.cctx = dl->cctx;
+    event.data.DownloadError.dc.ppos = dl->parent;
+    event.data.DownloadError.dc.pcctx = dl->parent->cctx;
+    dl->ctx->ecb(dl->ctx->ecbClosure,
+                &event);    
   }
-  root = dl;
-  while (root->parent != &dl->ctx->activeDownloads) {
-    root->completed += totalBytes;
-    root = root->parent;
-  }
-  root->completed += totalBytes;
-    
 
   if ( (ret == OK) &&
        (dl->is_recursive) &&
@@ -253,7 +251,10 @@
     char * dirBlock;
     int fd;
     char * fn;
+    size_t totalBytes;
+    struct ECRS_MetaData * md;
 
+    totalBytes = ECRS_fileSize(dl->uri);
     fn = MALLOC(strlen(dl->filename) + 3 + strlen(GNUNET_DIRECTORY_EXT));
     strcpy(fn, dl->filename);
     if (fn[strlen(fn)-1] == '/') {
@@ -298,51 +299,6 @@
     }
     FREE(fn);
   }
-  if (ret != OK) {
-    switch (dl->state) {
-    case FSUI_DOWNLOAD_ABORTED:
-      event.type = FSUI_download_aborted;
-      event.data.DownloadError.message = _("Download aborted.");
-      break;
-    case FSUI_DOWNLOAD_ERROR:
-      event.type = FSUI_download_error;
-      event.data.DownloadError.message = _("ECRS download failed (see logs).");
-      break;
-    case FSUI_DOWNLOAD_SUSPENDING:
-      event.type = FSUI_download_suspending;
-      event.data.DownloadError.message = _("ECRS download suspending.");
-      break;
-    default:
-      event.type = FSUI_download_error;
-      event.data.DownloadError.message = _("Unexpected download state.");
-      printf("State: %u\n", dl->state);
-      GE_BREAK(ectx, 0);
-    }
-    event.data.DownloadError.dc.pos = dl;
-    event.data.DownloadError.dc.cctx = dl->cctx;
-    event.data.DownloadError.dc.ppos = dl->parent;
-    event.data.DownloadError.dc.pcctx = dl->parent != NULL ? dl->parent->cctx 
: NULL;
-    dl->ctx->ecb(dl->ctx->ecbClosure,
-                &event);
-  } else {
-    GE_ASSERT(ectx, dl != &dl->ctx->activeDownloads);
-    while ( (dl != NULL) &&
-           (dl->ctx != NULL) &&
-           (dl != &dl->ctx->activeDownloads) ) {
-      event.type = FSUI_download_complete;
-      event.data.DownloadComplete.total = dl->total;
-      event.data.DownloadComplete.filename = dl->filename;
-      event.data.DownloadComplete.uri = dl->uri;
-      event.data.DownloadComplete.dc.pos = dl;
-      event.data.DownloadComplete.dc.cctx = dl->cctx;
-      event.data.DownloadComplete.dc.ppos = dl->parent;
-      event.data.DownloadComplete.dc.pcctx = dl->parent != NULL ? 
dl->parent->cctx : NULL;
-      dl->ctx->ecb(dl->ctx->ecbClosure,
-                  &event);
-      dl = dl->parent;
-    }
-  }
-  dl = cls;
 #if DEBUG_DTM
   GE_LOG(ectx, 
         GE_DEBUG | GE_REQUEST | GE_USER,
@@ -350,6 +306,7 @@
         dl->filename,
         ret == OK ? "COMPLETED" : "ABORTED");
 #endif
+  dl->runTime = get_time() - dl->startTime;
   return NULL;
 }
 
@@ -364,8 +321,7 @@
              const char * filename,
              FSUI_DownloadList * parent) {
   FSUI_DownloadList * dl;
-  FSUI_DownloadList * root;
-  unsigned long long totalBytes;
+  FSUI_Event event;
 
   GE_ASSERT(NULL, ctx != NULL);
   GE_ASSERT(NULL, parent != NULL);
@@ -375,9 +331,12 @@
     return NULL;
   }
   dl = MALLOC(sizeof(FSUI_DownloadList));
-  memset(dl, 0, sizeof(FSUI_DownloadList));
-  dl->startTime = get_time();
-  dl->state = FSUI_DOWNLOAD_PENDING;
+  memset(dl, 
+        0,
+        sizeof(FSUI_DownloadList));
+  dl->startTime = 0; /* not run at all so far! */
+  dl->runTime = 0; /* not run at all so far! */
+  dl->state = FSUI_PENDING;
   dl->is_recursive = is_recursive;
   dl->parent = parent;
   dl->is_directory = SYSERR; /* don't know */
@@ -389,14 +348,20 @@
   dl->child = NULL;
   dl->next = parent->child;
   parent->child = dl;  
-  totalBytes = ECRS_fileSize(uri);
 
-  root = dl;
-  while ( (root->parent != NULL) &&
-         (root->parent != &dl->ctx->activeDownloads) ) {
-    root = root->parent;
-    root->total += totalBytes;
-  }
+  /* signal start! */
+  event.type = FSUI_download_error;
+  event.data.DownloadStarted.filename = dl->filename;
+  event.data.DownloadStarted.total = ECRS_fileSize(uri);
+  event.data.DownloadStarted.uri = uri;
+  event.data.DownloadStarted.anonymityLevel = anonymityLevel;
+  event.data.DownloadStarted.dc.pos = dl;
+  event.data.DownloadStarted.dc.cctx = dl->cctx;
+  event.data.DownloadStarted.dc.ppos = dl->parent;
+  event.data.DownloadStarted.dc.pcctx = dl->parent->cctx; 
+  dl->cctx = ctx->ecb(ctx->ecbClosure,
+                     &event);
+
   return dl;
 }
 
@@ -429,11 +394,11 @@
 /**
  * Starts or stops download threads in accordance with thread pool
  * size and active downloads.  Call only while holding FSUI lock (or
- * during start/stop).
+ * during start/stop).  Called from cron job in fsui.c.
  *
  * @return YES if change done that may require re-trying
  */
-int updateDownloadThread(FSUI_DownloadList * list) {
+int FSUI_updateDownloadThread(FSUI_DownloadList * list) {
   struct GE_Context * ectx;
   FSUI_DownloadList * dpos;
   void * unused;
@@ -455,7 +420,7 @@
   /* should this one be started? */
   if ( (list->ctx->threadPoolSize
        > list->ctx->activeDownloadThreads) &&
-       (list->state == FSUI_DOWNLOAD_PENDING) &&
+       (list->state == FSUI_PENDING) &&
        ( (list->total > list->completed) ||
          (list->total == 0) ) ) {
 #if DEBUG_DTM
@@ -464,7 +429,7 @@
           "Download thread manager starts download of file `%s'\n",
           list->filename);
 #endif
-    list->state = FSUI_DOWNLOAD_ACTIVE;
+    list->state = FSUI_ACTIVE;
     list->handle = PTHREAD_CREATE(&downloadThread,
                                  list,
                                  32 * 1024);
@@ -474,14 +439,14 @@
       GE_LOG_STRERROR(ectx,
                      GE_ADMIN | GE_USER | GE_BULK | GE_ERROR,
                      "pthread_create");        
-      list->state = FSUI_DOWNLOAD_ERROR_JOINED;
+      list->state = FSUI_ERROR_JOINED;
     }
   }
 
   /* should this one be stopped? */
   if ( (list->ctx->threadPoolSize
        < list->ctx->activeDownloadThreads) &&
-       (list->state == FSUI_DOWNLOAD_ACTIVE) ) {
+       (list->state == FSUI_ACTIVE) ) {
 #if DEBUG_DTM
     GE_LOG(ectx, 
           GE_DEBUG | GE_REQUEST | GE_USER,
@@ -490,20 +455,20 @@
           list->ctx->activeDownloadThreads,
           list->ctx->threadPoolSize);
 #endif
-    list->state = FSUI_DOWNLOAD_SUSPENDING;
+    list->state = FSUI_SUSPENDING;
     GE_ASSERT(ectx, list->handle != NULL);
     PTHREAD_STOP_SLEEP(list->handle);
     PTHREAD_JOIN(list->handle,
                 &unused);
     list->ctx->activeDownloadThreads--;
-    list->state = FSUI_DOWNLOAD_PENDING;
+    list->state = FSUI_PENDING;
     ret = YES;
   }
 
   /* has this one "died naturally"? */
-  if ( (list->state == FSUI_DOWNLOAD_COMPLETED) ||
-       (list->state == FSUI_DOWNLOAD_ABORTED) ||
-       (list->state == FSUI_DOWNLOAD_ERROR) ) {       
+  if ( (list->state == FSUI_COMPLETED) ||
+       (list->state == FSUI_ABORTED) ||
+       (list->state == FSUI_ERROR) ) {       
 #if DEBUG_DTM
     GE_LOG(ectx, 
           GE_DEBUG | GE_REQUEST | GE_USER,
@@ -519,7 +484,7 @@
 
   dpos = list->child;
   while (dpos != NULL) {
-    if (YES == updateDownloadThread(dpos))
+    if (YES == FSUI_updateDownloadThread(dpos))
       ret = YES;
     dpos = dpos->next;
   }
@@ -528,66 +493,54 @@
 
 
 /**
- * Free the subtree (assumes all threads have already been stopped and
- * that the FSUI lock is either held or that we are in FSUI stop!).
+ * Abort a download (and all child-downloads).
+ *
+ * @return SYSERR if no such download is pending,
+ *         NO if the download has already finished
  */
-void freeDownloadList(FSUI_DownloadList * list) {
-  FSUI_DownloadList * dpos;
-  int i;
+int FSUI_abortDownload(struct FSUI_Context * ctx,
+                      struct FSUI_DownloadList * dl) {
+  FSUI_Event event;
+  struct FSUI_DownloadList * c;
 
-  GE_ASSERT(NULL, list->state != FSUI_DOWNLOAD_ACTIVE);
-
-  /* first, find our predecessor and
-     unlink us from the tree! */
-  dpos = list->parent;
-  GE_ASSERT(NULL, dpos != NULL);
-  if (dpos->child == list) {
-    dpos->child = list->next;
-  } else {
-    dpos = dpos->child;
-    while ( (dpos != NULL) &&
-           (dpos->next != list) )
-      dpos = dpos->next;
-    GE_ASSERT(NULL, dpos != NULL);
-    dpos->next = list->next;    
-  }
-
-  /* then, free all of our children */
-  while (list->child != NULL)
-    freeDownloadList(list->child);
-
-  /* finally, free this node and its data */
-  ECRS_freeUri(list->uri);
-  FREE(list->filename);
-  for (i=list->completedDownloadsCount-1;i>=0;i--)
-    ECRS_freeUri(list->completedDownloads[i]);
-  GROW(list->completedDownloads,
-       list->completedDownloadsCount,
-       0);
-  FREE(list);
+  GE_ASSERT(ctx->ectx, dl != NULL);
+  c = dl->child;
+  while (c != NULL) {
+    FSUI_abortDownload(ctx, c);
+    c = c->next;
+  }    
+  if ( (dl->state != FSUI_ACTIVE) &&
+       (dl->state != FSUI_PENDING) )
+    return NO;
+  dl->state = FSUI_ABORTED;
+  PTHREAD_STOP_SLEEP(dl->handle);
+  event.type = FSUI_download_aborted;
+  event.data.DownloadAborted.dc.pos = dl;
+  event.data.DownloadAborted.dc.cctx = dl->cctx;
+  event.data.DownloadAborted.dc.ppos = dl->parent;
+  event.data.DownloadAborted.dc.pcctx = dl->parent->cctx;
+  ctx->ecb(ctx->ecbClosure,
+          &event);
+  return OK;
 }
 
 /**
- * Abort a download.
+ * Stops a download (and all downloads that are
+ * child downloads of this download).
  *
  * @return SYSERR if no such download is pending
  */
 int FSUI_stopDownload(struct FSUI_Context * ctx,
                      struct FSUI_DownloadList * dl) {
-  FSUI_DownloadList * prev;
-  struct GE_Context * ectx;
-  unsigned int backup;
+  void * unused;
+  struct FSUI_DownloadList * prev;
+  FSUI_Event event;
+  int i;
 
-  ectx = ctx->ectx;
-  if (dl == NULL) {
-    GE_BREAK(ectx, 0);
-    return SYSERR;
-  }
-#if 0
-  GE_LOG(ectx,
-        GE_DEBUG | GE_REQUEST | GE_USER,
-        "FSUI_stopDownload called.\n");
-#endif
+  GE_ASSERT(ctx->ectx, dl != NULL);
+  while (dl->child != NULL)
+    FSUI_stopDownload(ctx,
+                     dl->child);
   MUTEX_LOCK(ctx->lock);
   prev = (dl->parent != NULL) ? dl->parent->child : ctx->activeDownloads.child;
   while ( (prev != dl) &&
@@ -596,17 +549,38 @@
     prev = prev->next;
   if (prev == NULL) {
     MUTEX_UNLOCK(ctx->lock);
-    GE_LOG(ectx, 
+    GE_LOG(ctx->ectx, 
           GE_DEBUG | GE_REQUEST | GE_USER,
           "FSUI_stopDownload failed to locate download.\n");
     return SYSERR;
   }
-  backup = ctx->threadPoolSize;
-  ctx->threadPoolSize = 0;
-  updateDownloadThread(dl);
-  freeDownloadList(dl);
-  ctx->threadPoolSize = backup;
+  if (prev == dl) 
+    dl->parent->child = dl->next; /* first child of parent */
+  else 
+    prev->next = dl->next; /* not first child */  
   MUTEX_UNLOCK(ctx->lock);
+  if ( (dl->state == FSUI_COMPLETED) ||
+       (dl->state == FSUI_ABORTED) ||
+       (dl->state == FSUI_ERROR) ) {
+    PTHREAD_JOIN(dl->handle,
+                &unused);
+    dl->state++; /* add _JOINED */
+  }
+  event.type = FSUI_download_stopped;
+  event.data.DownloadStopped.dc.pos = dl;
+  event.data.DownloadStopped.dc.cctx = dl->cctx;
+  event.data.DownloadStopped.dc.ppos = dl->parent;
+  event.data.DownloadStopped.dc.pcctx = dl->parent->cctx;
+  ctx->ecb(ctx->ecbClosure,
+          &event);
+  for (i=dl->completedDownloadsCount-1;i>=0;i--)
+    ECRS_freeUri(dl->completedDownloads[i]);
+  GROW(dl->completedDownloads,
+       dl->completedDownloadsCount,
+       0);
+  ECRS_freeUri(dl->uri);
+  FREE(dl->filename);
+  FREE(dl);
   return OK;
 }
 

Modified: GNUnet/src/applications/fs/fsui/fsui.c
===================================================================
--- GNUnet/src/applications/fs/fsui/fsui.c      2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/fsui.c      2006-10-13 03:09:42 UTC (rev 
3482)
@@ -24,9 +24,11 @@
  * @author Christian Grothoff
  *
  * TODO:
- * - upload serialize/deserialize/resume
- * - unindex deserialize/resume
- * - events for suspend (!)
+ * - upload tree representation (currently flat list!)
+ * - download tree free memory
+ * - resume signaling
+ * - actual resuming (start threads)
+ * - better ETA calculation for download resume
  */
 
 #include "platform.h"
@@ -36,362 +38,13 @@
 
 #define DEBUG_PERSISTENCE NO
 
+/* ***************** CRON code ***************** */
+
 #define FSUI_UDT_FREQUENCY (2 * cronSECONDS)
 
-#define READINT(a) \
-  if (sizeof(int) != READ(fd, &big, sizeof(int))) \
-    goto ERR;                                    \
-  else \
-    a = ntohl(big)
-#define READLONG(a) \
-  if (sizeof(long long) != READ(fd, &bigl, sizeof(long long))) \
-    goto ERR;                                                 \
-  else \
-    a = ntohll(bigl)
-
-static struct ECRS_URI * readURI(struct GE_Context * ectx,
-                                int fd) {
-  char * buf;
-  unsigned int big;
-  struct ECRS_URI * ret;
-  unsigned int size;
-
-  READINT(size);
-  buf = MALLOC(size+1);
-  buf[size] = '\0';
-  if (size != READ(fd,
-                  buf,
-                  size)) {
-    FREE(buf);
-    return NULL;
-  }
-  ret = ECRS_stringToUri(ectx, buf);
-  FREE(buf);
-  return ret;
- ERR:
-  return NULL;
-}
-
-static void doResumeEvents(struct FSUI_DownloadList * ret,
-                          FSUI_Context * ctx) {
-  FSUI_Event event;
-
-  while (ret != NULL) {
-    event.type = FSUI_download_resuming;
-    event.data.DownloadResuming.dc.pos = ret;
-    event.data.DownloadResuming.dc.cctx = ret->cctx;
-    event.data.DownloadResuming.dc.ppos = ret->parent;
-    event.data.DownloadResuming.dc.pcctx = ret->parent != NULL ? 
ret->parent->cctx : NULL;
-    event.data.DownloadResuming.eta = get_time(); /* best guess */
-    event.data.DownloadResuming.total = ret->total;
-    event.data.DownloadResuming.completed = ret->completedFile;
-    event.data.DownloadResuming.anonymityLevel = ret->anonymityLevel;
-    event.data.DownloadResuming.uri = ret->uri;
-    ret->cctx = ctx->ecb(ctx->ecbClosure, &event);
-    if (ret->child != NULL)
-      doResumeEvents(ret->child,
-                    ctx);
-    ret = ret->next;
-  }
-}
-
 /**
- * (Recursively) read a download list from the given fd.  The returned
- * pointer is expected to be integrated into the tree either as a next
- * or child pointer such that the given parent becomes the parent of the
- * returned node.
- *
- * @return NULL on error AND on read of empty
- *  list (these two cannot be distinguished)
+ * Cron job for download load management.
  */
-static FSUI_DownloadList * readDownloadList(struct GE_Context * ectx,
-                                           int fd,
-                                           FSUI_Context * ctx,
-                                           FSUI_DownloadList * parent) {
-  char zaro;
-  FSUI_DownloadList * ret;
-  unsigned int big;
-  unsigned long long bigl;
-  int i;
-  int ok;
-
-  GE_ASSERT(ectx, ctx != NULL);
-  if (1 != READ(fd, &zaro, sizeof(char))) {
-    GE_BREAK(ectx, 0);
-    return NULL;
-  }
-  if (zaro == '\0') 
-    return NULL;
-  ret = MALLOC(sizeof(FSUI_DownloadList));
-  memset(ret,
-        0,
-        sizeof(FSUI_DownloadList));
-  ret->ctx = ctx;
-  READINT(ret->is_recursive);
-  READINT(ret->is_directory);
-  READINT(ret->anonymityLevel);
-  READINT(ret->completedDownloadsCount);
-  READINT(ret->state);
-  switch (ret->state) { /* try to correct errors */
-  case FSUI_DOWNLOAD_ACTIVE:
-    ret->state = FSUI_DOWNLOAD_PENDING;
-    break;
-  case FSUI_DOWNLOAD_PENDING:
-  case FSUI_DOWNLOAD_COMPLETED_JOINED:
-  case FSUI_DOWNLOAD_ABORTED_JOINED:
-  case FSUI_DOWNLOAD_ERROR_JOINED:
-    break;
-  case FSUI_DOWNLOAD_ERROR:
-    ret->state = FSUI_DOWNLOAD_ERROR_JOINED;
-    break;
-  case FSUI_DOWNLOAD_ABORTED:
-    ret->state = FSUI_DOWNLOAD_ABORTED_JOINED;
-    break;
-  case FSUI_DOWNLOAD_COMPLETED:
-    ret->state = FSUI_DOWNLOAD_COMPLETED_JOINED;
-    break;
-  default:
-    ret->state = FSUI_DOWNLOAD_PENDING;
-    break;
-  }
-  READINT(big);
-  if (big > 1024 * 1024) {
-    GE_BREAK(ectx, 0);
-    goto ERR;
-  }
-  ret->filename = MALLOC(big+1);
-  if (big != READ(fd, ret->filename, big)) {
-    GE_BREAK(ectx, 0);
-    goto ERR;
-  }
-  ret->filename[big] = '\0';
-  READLONG(ret->total);
-  READLONG(ret->completed);
-  ret->completedFile = 0;
-  READLONG(ret->startTime);
-  ret->startTime = get_time() - ret->startTime;
-  ret->uri
-    = readURI(ectx, fd);
-  if (ret->completedDownloadsCount > 0)
-    ret->completedDownloads
-      = MALLOC(sizeof(struct ECRS_URI *) *
-              ret->completedDownloadsCount);
-  else
-    ret->completedDownloads
-      = NULL;
-  ok = ret->uri != NULL;
-  for (i=0;i<ret->completedDownloadsCount;i++) {
-    ret->completedDownloads[i]
-      = readURI(ectx, fd);
-    if (ret->completedDownloads[i] == NULL) 
-      ok = NO;    
-  }
-  if (NO == ok) {
-    GE_BREAK(ectx, 0);
-    goto ERR;
-  }
-  ret->parent = parent;
-  ret->next = readDownloadList(ectx,
-                              fd,
-                              ctx,
-                              parent);
-  ret->child = readDownloadList(ectx,
-                               fd,
-                               ctx,
-                               ret);
-#if DEBUG_PERSISTENCE
-  GE_LOG(ectx, 
-        GE_DEBUG | GE_REQUEST | GE_USER,
-        "FSUI persistence: restoring download `%s': (%llu, %llu)\n",
-        ret->filename,
-        ret->completed,
-        ret->total);
-#endif
-  return ret;
- ERR:
-  FREENONNULL(ret->filename);
-  if (ret->uri != NULL)
-    ECRS_freeUri(ret->uri);
-  for (i=0;i<ret->completedDownloadsCount;i++) {
-    if (ret->completedDownloads[i] != NULL)
-      ECRS_freeUri(ret->completedDownloads[i]);
-  }
-  FREE(ret);
-  GE_LOG(ectx,
-        GE_WARNING | GE_BULK | GE_USER,
-        _("FSUI persistence: error restoring download\n"));
-  return NULL;
-}
-
-static void WRITEINT(int fd,
-                    int val) {
-  int big;
-  big = htonl(val);
-  WRITE(fd, &big, sizeof(int));
-}
-
-static void WRITELONG(int fd,
-                     long long val) {
-  long long big;
-  big = htonll(val);
-  WRITE(fd, &big, sizeof(long long));
-}
-
-static void writeURI(int fd,
-                    const struct ECRS_URI * uri) {
-  char * buf;
-  unsigned int size;
-
-  buf = ECRS_uriToString(uri);
-  size = strlen(buf);
-  WRITEINT(fd, size);
-  WRITE(fd,
-       buf,
-       size);
-  FREE(buf);
-}
-
-static void WRITESTRING(int fd,
-                       const char * name) {
-  WRITEINT(fd,
-          strlen(name));
-  WRITE(fd,
-       name,
-       strlen(name));
-}
-
-/**
- * (recursively) write a download list.
- */
-static void writeDownloadList(struct GE_Context * ectx,
-                             int fd,
-                             FSUI_Context * ctx,
-                             FSUI_DownloadList * list) {
-  static char zero = '\0';
-  static char nonzero = '+';
-  int i;
-  FSUI_Event event;
-
-  if (list == NULL) {
-    WRITE(fd, &zero, sizeof(char));
-    return;
-  }
-#if DEBUG_PERSISTENCE
-  GE_LOG(ectx,
-        GE_DEBUG | GE_REQUEST | GE_USER,
-        "Serializing download state of download `%s': (%llu, %llu)\n",
-        list->filename,
-        list->completed,
-        list->total);
-#endif
-  WRITE(fd, &nonzero, sizeof(char));
-
-  WRITEINT(fd, list->is_recursive);
-  WRITEINT(fd, list->is_directory);
-  WRITEINT(fd, list->anonymityLevel);
-  WRITEINT(fd, list->completedDownloadsCount);
-  WRITEINT(fd, list->state);
-  WRITEINT(fd, strlen(list->filename));
-  WRITE(fd,
-       list->filename,
-       strlen(list->filename));
-  WRITELONG(fd, list->total);
-  WRITELONG(fd, list->completed);
-  WRITELONG(fd, get_time() - list->startTime);
-  writeURI(fd, list->uri);
-  for (i=0;i<list->completedDownloadsCount;i++)
-    writeURI(fd, list->completedDownloads[i]);
-  writeDownloadList(ectx,
-                   fd,
-                   ctx,
-                   list->next);
-  writeDownloadList(ectx,
-                   fd,
-                   ctx,
-                   list->child);
-  event.type = FSUI_download_suspending;
-  event.data.DownloadSuspending.dc.pos = list;
-  event.data.DownloadSuspending.dc.cctx = list->cctx;
-  event.data.DownloadSuspending.dc.ppos = list->parent;
-  event.data.DownloadSuspending.dc.pcctx = list->parent != NULL ? 
list->parent->cctx : NULL; 
-  ctx->ecb(ctx->ecbClosure, &event);
-}
-
-/**
- * Read file info from file.
- *
- * @return OK on success, SYSERR on error
- */
-static int readFileInfo(struct GE_Context * ectx,
-                       int fd,
-                       ECRS_FileInfo * fi) {
-  unsigned int size;
-  unsigned int big;
-  char * buf;
-
-  fi->meta = NULL;
-  fi->uri = NULL;
-  READINT(size);
-  if (size > 1024 * 1024) {
-    GE_BREAK(ectx, 0);
-    return SYSERR;
-  }
-  buf = MALLOC(size);
-  if (size != READ(fd,
-                  buf,
-                  size)) {
-    FREE(buf);
-    GE_BREAK(ectx, 0);
-    return SYSERR;
-  }
-  fi->meta = ECRS_deserializeMetaData(ectx,
-                                     buf,
-                                     size);
-  if (fi->meta == NULL) {
-    FREE(buf);
-    GE_BREAK(ectx, 0);
-    return SYSERR;
-  }
-  FREE(buf);
-
-  fi->uri
-    = readURI(ectx, fd);
-  if (fi->uri == NULL) {
-    ECRS_freeMetaData(fi->meta);
-    fi->meta = NULL;
-    GE_BREAK(ectx, 0);
-    return SYSERR;
-  }
-  return OK;
- ERR:
-  GE_BREAK(ectx, 0);
-  return SYSERR;
-}
-
-static void writeFileInfo(struct GE_Context * ectx,
-                         int fd,
-                         const ECRS_FileInfo * fi) {
-  unsigned int size;
-  char * buf;
-
-  size = ECRS_sizeofMetaData(fi->meta,
-                            ECRS_SERIALIZE_FULL | ECRS_SERIALIZE_NO_COMPRESS);
-  if (size > 1024 * 1024)
-    size = 1024 * 1024;
-  buf = MALLOC(size);
-  ECRS_serializeMetaData(ectx,
-                        fi->meta,
-                        buf,
-                        size,
-                        ECRS_SERIALIZE_PART | ECRS_SERIALIZE_NO_COMPRESS);
-  WRITEINT(fd, size);
-  WRITE(fd,
-       buf,
-       size);
-  FREE(buf);
-  writeURI(fd, fi->uri);
-}
-
 static void updateDownloadThreads(void * c) {
   FSUI_Context * ctx = c;
   FSUI_DownloadList * dpos;
@@ -405,12 +58,37 @@
           "Download thread manager schedules pending downloads...\n");
 #endif
   while (dpos != NULL) {
-    updateDownloadThread(dpos);
+    FSUI_updateDownloadThread(dpos);
     dpos = dpos->next;
   }
   MUTEX_UNLOCK(ctx->lock);
 }
 
+/* ******************* START code *********************** */
+
+static void signalDownloadResume(struct FSUI_DownloadList * ret,
+                                FSUI_Context * ctx) {
+  FSUI_Event event;
+
+  while (ret != NULL) {
+    event.type = FSUI_download_resumed;
+    event.data.DownloadResumed.dc.pos = ret;
+    event.data.DownloadResumed.dc.cctx = ret->cctx;
+    event.data.DownloadResumed.dc.ppos = ret->parent;
+    event.data.DownloadResumed.dc.pcctx = ret->parent->cctx;
+    event.data.DownloadResumed.eta = get_time(); /* FIXME: can do better here! 
*/
+    event.data.DownloadResumed.total = ret->total;
+    event.data.DownloadResumed.completed = ret->completed;
+    event.data.DownloadResumed.anonymityLevel = ret->anonymityLevel;
+    event.data.DownloadResumed.uri = ret->uri;
+    ret->cctx = ctx->ecb(ctx->ecbClosure, &event);
+    if (ret->child != NULL)
+      signalDownloadResume(ret->child,
+                          ctx);
+    ret = ret->next;
+  }
+}
+
 /**
  * Start FSUI manager.  Use the given progress callback to notify the
  * UI about events.  Start processing pending activities that were
@@ -429,21 +107,18 @@
   FSUI_Event event;
   FSUI_Context * ret;
   FSUI_SearchList * list;
-  ResultPending * rp;
   char * fn;
   char * gh;
-  int fd;
-  int i;
 
   GE_ASSERT(ectx, cfg != NULL);
   ret = MALLOC(sizeof(FSUI_Context));
-  memset(ret, 0, sizeof(FSUI_Context));
+  memset(ret, 
+        0, 
+        sizeof(FSUI_Context));
   ret->activeDownloads.state
-    = FSUI_DOWNLOAD_PENDING; /* !? */
-  ret->activeDownloads.ctx
-    = ret;
-  ret->cfg
-    = cfg;
+    = FSUI_PENDING; /* !? */
+  ret->activeDownloads.ctx = ret;
+  ret->cfg = cfg;
   ret->ecb = cb;
   ret->ecbClosure = closure;
   ret->threadPoolSize = threadPoolSize;
@@ -462,6 +137,8 @@
   strcat(fn, DIR_SEPARATOR_STR);
   strcat(fn, name);
   ret->name = fn;
+
+  /* 1) read state  in */
   if (doResume) {
     ret->ipc = IPC_SEMAPHORE_CREATE(ectx,
                                    fn,
@@ -478,310 +155,108 @@
           GE_INFO | GE_REQUEST | GE_USER,
           "Aquired IPC lock.\n");
 #endif
-    fd = -1;
     strcat(fn, ".res");
-    if (0 == ACCESS(fn, R_OK))
-      fd = disk_file_open(ectx,
-                         fn,
-                         O_RDONLY);
-    if (fd != -1) {
-      char magic[8];
-      unsigned int big;
+    FSUI_deserialize(ret);
+  } else {
+    ret->ipc = NULL;
+  }
+  ret->lock = MUTEX_CREATE(YES);
 
-      /* ****** check magic ******* */
-      if (8 != READ(fd, magic, 8)) {
-       GE_BREAK(ectx, 0);
-       goto WARN;
-      }
-      if (0 != memcmp(magic,
-                     "FSUI00\n\0",
-                     8)) {
-       GE_BREAK(ectx, 0);
-       goto WARN;
-      }
-      /* ******* deserialize state **** */
+  /* 2) do resume events */
+  /* 2a) signal download restarts */
+  signalDownloadResume(ret->activeDownloads.child,
+                      ret);
+  /* 2b) signal search restarts */
 
-      /* deserialize collection data */
-      if (sizeof(unsigned int) !=
-         READ(fd, &big, sizeof(unsigned int))) {
-       GE_BREAK(ectx, 0);
-       goto WARN;
-      }
-      if (ntohl(big) > 16 * 1024 * 1024) {
-       GE_BREAK(ectx, 0);
-       goto WARN;
-      }
-      if (big == 0) {
-       ret->collectionData = NULL;
-      } else {
-       ret->collectionData
-         = MALLOC(ntohl(big));
-       if (ntohl(big) - sizeof(unsigned int) !=
-           READ(fd,
-                &ret->collectionData[1],
-                ntohl(big) - sizeof(unsigned int))) {
-         FREE(ret->collectionData);
-         ret->collectionData = NULL;
-         GE_BREAK(ectx, 0);
-         goto WARN;
-       }
-      }
+       event.type = FSUI_search_resumed;
+       event.data.SearchResumed.sc.pos = list;
+       event.data.SearchResumed.sc.cctx = NULL;
+       event.data.SearchResumed.fis = list->resultsReceived;
+       event.data.SearchResumed.fisSize = list->sizeResultsReceived;
+       event.data.SearchResumed.anonymityLevel = list->anonymityLevel;
+       event.data.SearchResumed.searchURI = list->uri;
+       list->cctx = cb(closure, &event);       
 
-      /* deserialize pending searches! */
-      while (1) {
-       char * buf;
+  /* 2c) signal upload restarts */
 
-       if (sizeof(unsigned int) !=
-           READ(fd, &big, sizeof(unsigned int))) {
-         GE_BREAK(ectx, 0);    
-         goto WARN;
-       }
-       if (ntohl(big) == 0)
-         break;
-       if (ntohl(big) > 1024 * 1024) {
-         GE_BREAK(ectx, 0);    
-         goto WARN;
-       }
-       buf
-         = MALLOC(ntohl(big)+1);
-       buf[ntohl(big)] = '\0'; 
-       if (ntohl(big) !=
-           READ(fd,
-                buf,
-                ntohl(big))) {
-         FREE(buf);
-         GE_BREAK(ectx, 0);    
-         goto WARN;
-       }
-       list
-         = MALLOC(sizeof(FSUI_SearchList));    
-       list->uri
-         = ECRS_stringToUri(ectx, buf);
-       FREE(buf);
-       if (list->uri == NULL) {
-         FREE(list);
-         GE_BREAK(ectx, 0);    
-         goto WARN;
-       }
-       if (! ECRS_isKeywordUri(list->uri)) {
-         ECRS_freeUri(list->uri);
-         FREE(list);
-         GE_BREAK(ectx, 0);            
-         goto WARN;
-       }
-       list->numberOfURIKeys
-         = ECRS_countKeywordsOfUri(list->uri);
-       if (sizeof(unsigned int) !=
-           READ(fd, &big, sizeof(unsigned int))) {
-         ECRS_freeUri(list->uri);
-         FREE(list);   
-         GE_BREAK(ectx, 0);
-         goto WARN;
-       }
-       list->anonymityLevel
-         = ntohl(big);
-       if (sizeof(unsigned int) !=
-           READ(fd, &big, sizeof(unsigned int))) {
-         ECRS_freeUri(list->uri);
-         FREE(list);
-         GE_BREAK(ectx, 0);
-         goto WARN;
-       }
-       list->sizeResultsReceived
-         = ntohl(big);
-       if (sizeof(unsigned int) !=
-           READ(fd, &big, sizeof(unsigned int))) {
-         ECRS_freeUri(list->uri);
-         FREE(list);
-         GE_BREAK(ectx, 0);
-         goto WARN;
-       }
-       list->sizeUnmatchedResultsReceived
-         = ntohl(big);
-       if ( (list->sizeResultsReceived > 1024*1024) ||
-            (list->sizeUnmatchedResultsReceived > 1024*1024) ) {
-         ECRS_freeUri(list->uri);
-         FREE(list);
-         GE_BREAK(ectx, 0);
-         goto WARN;
-       }
-       if (list->sizeResultsReceived > 0)
-         list->resultsReceived
-           = MALLOC(list->sizeResultsReceived *
-                    sizeof(ECRS_FileInfo));
-       else
-         list->resultsReceived
-           = NULL;
-       if (list->sizeUnmatchedResultsReceived > 0)
-         list->unmatchedResultsReceived
-           = MALLOC(list->sizeUnmatchedResultsReceived *
-                    sizeof(ResultPending));
-       else
-         list->unmatchedResultsReceived
-           = NULL;
-       for (i=0;i<list->sizeResultsReceived;i++)
-         readFileInfo(ectx,
-                      fd,
-                      &list->resultsReceived[i]);
-       for (i=0;i<list->sizeUnmatchedResultsReceived;i++) {
-         rp = &list->unmatchedResultsReceived[i];
-         readFileInfo(ectx,
-                      fd,
-                      &rp->fi);
-       
-         if (sizeof(unsigned int) !=
-             READ(fd,
-                  &big,
-                  sizeof(unsigned int))) {
-           GE_BREAK(ectx, 0);
-           goto WARNL;
-         }
-         rp->matchingKeyCount
-           = ntohl(big);
-         if ( (rp->matchingKeyCount > 1024) ||
-              (rp->matchingKeyCount >
-               list->numberOfURIKeys) ) {
-           GE_BREAK(ectx, 0);
-           goto WARNL;
-         }
-       
-         if (rp->matchingKeyCount > 0)
-           rp->matchingKeys
-             = MALLOC(sizeof(HashCode512) *
-                      rp->matchingKeyCount);
-         else
-           rp->matchingKeys
-             = NULL;
-         if (sizeof(HashCode512) *
-             rp->matchingKeyCount !=
-             READ(fd,
-                  rp->matchingKeys,
-                  sizeof(HashCode512) *
-                  rp->matchingKeyCount)) {
-           GE_BREAK(ectx, 0);
-           goto WARNL;
-         }
-       }
-       
-       
-       list->signalTerminate
-         = NO;
-       list->ctx
-         = ret;
-       /* start search thread! */
+  /* 2d) signal unindex restarts */
+
+  /* 3) restart processing */
+  ret->cron = cron_create(ectx);  
+  /* 3a) resume downloads */
+  cron_add_job(ret->cron,
+              &updateDownloadThreads,
+              0,
+              FSUI_UDT_FREQUENCY,
+              ret);
+  cron_start(ret->cron);
+  /* 3b) resume uploads */
+
+  /* 3c) resume unindexing */
+
+  /* 3d) resume searching */
+
 #if DEBUG_PERSISTENCE
        GE_LOG(ectx, 
               GE_DEBUG | GE_REQUEST | GE_USER,
               "FSUI persistence: restarting search\n");
 #endif
-       list->handle = PTHREAD_CREATE(&searchThread,
+       list->handle = PTHREAD_CREATE(&FSUI_searchThread,
                                      list,
                                      32 * 1024);
        if (list->handle == NULL)
          GE_DIE_STRERROR(ectx,
                          GE_FATAL | GE_ADMIN | GE_IMMEDIATE,
                          "pthread_create");
-       
-       /* finally: prepend to list */
-       list->next
-         = ret->activeSearches;
-       ret->activeSearches
-         = list;
-       /* then: signal event handler! */
-       event.type = FSUI_search_resuming;
-       event.data.SearchResuming.sc.pos = list;
-       event.data.SearchResuming.sc.cctx = NULL;
-       event.data.SearchResuming.fis = list->resultsReceived;
-       event.data.SearchResuming.fisSize = list->sizeResultsReceived;
-       event.data.SearchResuming.anonymityLevel = list->anonymityLevel;
-       event.data.SearchResuming.searchURI = list->uri;
-       list->cctx = cb(closure, &event);       
-      }
-      memset(&ret->activeDownloads,
-            0,
-            sizeof(FSUI_DownloadList));
-      ret->activeDownloads.child
-       = readDownloadList(ectx,
-                          fd,
-                          ret,
-                          &ret->activeDownloads);
-      doResumeEvents(ret->activeDownloads.child,
-                    ret);
 
-      /* deserialize uploads */
-      while (1) {
-       if (sizeof(unsigned int) !=
-           READ(fd, &big, sizeof(unsigned int))) {
-         GE_BREAK(ectx, 0);
-         goto WARN;
-       }
-       if (ntohl(big) != 1) 
-         break; /* no more uploads */
-       
 
-      }
+  return ret;
+}
 
-      /* success, read complete! */
-      goto END;
-    WARNL:
-      for (i=0;i<list->sizeResultsReceived;i++) {
-       if (list->resultsReceived[i].uri != NULL)
-         ECRS_freeUri(list->resultsReceived[i].uri);
-       if (list->resultsReceived[i].meta != NULL)
-         ECRS_freeMetaData(list->resultsReceived[i].meta);     
-      }
-      GROW(list->resultsReceived,
-          list->sizeResultsReceived,
-          0);
-      for (i=0;i<list->sizeUnmatchedResultsReceived;i++) {
-       rp = &list->unmatchedResultsReceived[i];
-       
-       if (rp->fi.uri != NULL)
-         ECRS_freeUri(rp->fi.uri);
-       if (rp->fi.meta != NULL)
-         ECRS_freeMetaData(rp->fi.meta);
-       FREENONNULL(rp->matchingKeys);
-      }
-      GROW(list->resultsReceived,
-          list->sizeResultsReceived,
-          0);
-    WARN:
-      GE_LOG(ectx, 
-            GE_WARNING | GE_BULK | GE_USER,
-            _("FSUI state file `%s' had syntax error at offset %u.\n"),
-            fn,
-         lseek(fd, 0, SEEK_CUR));
-    END:
-      CLOSE(fd);
-      UNLINK(fn);
-    } else {
-      if (errno != ENOENT)
-       GE_LOG_STRERROR_FILE(ectx,
-                            GE_WARNING | GE_BULK | GE_USER,
-                            "open",
-                            fn);
-    }
-  } else {
-    ret->ipc = NULL;
+/* ******************* STOP code *********************** */
+
+/**
+ * (recursively) signal download suspension.
+ */
+static void signalDownloadSuspend(struct GE_Context * ectx,
+                                 FSUI_Context * ctx,
+                                 FSUI_DownloadList * list) {
+  FSUI_Event event;
+  while (list != NULL) {
+    signalDownloadSuspend(ectx,
+                         ctx,
+                         list->child);
+    event.type = FSUI_download_suspended;
+    event.data.DownloadSuspended.dc.pos = list;
+    event.data.DownloadSuspended.dc.cctx = list->cctx;
+    event.data.DownloadSuspended.dc.ppos = list->parent;
+    event.data.DownloadSuspended.dc.pcctx = list->parent->cctx; 
+    ctx->ecb(ctx->ecbClosure, &event);
+    list = list->next;
   }
-  ret->lock = MUTEX_CREATE(YES);
-  ret->cron = cron_create(ectx);  
-  cron_add_job(ret->cron,
-              &updateDownloadThreads,
-              0,
-              FSUI_UDT_FREQUENCY,
-              ret);
-  cron_start(ret->cron);
-  return ret;
 }
 
 /**
+ * (recursively) free download list
+ */
+static void freeDownloadList(FSUI_DownloadList * list) {
+  FSUI_DownloadList *  next;
+  
+  while (list != NULL) {
+    freeDownloadList(list->child);
+    /* FIXME: free memory! */
+    next = list->next;
+    FREE(list);
+    list = next;
+  }
+}
+
+/**
  * Stop all processes under FSUI control (serialize state, continue
  * later if possible).
  */
 void FSUI_stop(struct FSUI_Context * ctx) {
   struct GE_Context * ectx;
-  FSUI_ThreadList * tpos;
   FSUI_SearchList * spos;
   FSUI_DownloadList * dpos;
   FSUI_UnindexList * xpos;
@@ -789,8 +264,6 @@
   FSUI_Event event;
   void * unused;
   int i;
-  int fd;
-  int big;
 
   ectx = ctx->ectx;
   if (ctx->ipc != NULL)
@@ -798,123 +271,89 @@
           GE_INFO | GE_REQUEST | GE_USER,
           "FSUI shutdown.  This may take a while.\n");
 
+  /* 1) stop everything */
   cron_stop(ctx->cron);
   cron_del_job(ctx->cron,
               &updateDownloadThreads,
               FSUI_UDT_FREQUENCY,
               ctx);
   cron_destroy(ctx->cron);
-  /* first, stop all download threads
-     by reducing the thread pool size to 0 */
+
+  /* 1a) stop downloading */
   ctx->threadPoolSize = 0;
   dpos = ctx->activeDownloads.child;
   while (dpos != NULL) {
-    updateDownloadThread(dpos);
+    FSUI_updateDownloadThread(dpos);
     dpos = dpos->next;
   }
-
-  /* then, wait for all modal threads to complete */
-  while (ctx->activeThreads != NULL) {
-    tpos = ctx->activeThreads;
-    ctx->activeThreads = tpos->next;
-    PTHREAD_JOIN(tpos->handle, &unused);
-    FREE(tpos);
+  /* 1b) stop searching */
+  spos = ctx->activeSearches;
+  while (spos != NULL) {
+    spos->signalTerminate = YES;
+    PTHREAD_STOP_SLEEP(spos->handle);
+    PTHREAD_JOIN(spos->handle, &unused);
+    spos = spos->next;
   }
+  /* 1c) stop unindexing */
+  xpos = ctx->unindexOperations;
+  while (xpos != NULL) {
+    xpos->force_termination = YES;
+    PTHREAD_STOP_SLEEP(xpos->handle);
+    PTHREAD_JOIN(xpos->handle, &unused);    
+    xpos = xpos->next;    
+  }
+  /* 1d) stop uploading */
+  upos = ctx->activeUploads;
+  while (upos != NULL) {
+    upos->force_termination = YES;
+    PTHREAD_STOP_SLEEP(upos->handle);
+    PTHREAD_JOIN(upos->handle, &unused);
+    upos = upos->next;
+  } 
 
-  /* next, serialize all of the FSUI state */
-  if (ctx->ipc != NULL) {
-    fd = disk_file_open(ectx,
-                       ctx->name,
-                       O_CREAT|O_TRUNC|O_WRONLY,
-                       S_IRUSR|S_IWUSR);
-    if (fd != -1) {
-      WRITE(fd,
-           "FSUI00\n\0",
-           8); /* magic */
-    }
-#if DEBUG_PERSISTENCE
-    GE_LOG(ectx, 
-          GE_DEBUG | GE_REQUEST | GE_USER,
-          "Serializing FSUI state...\n");
-#endif
-  } else {
-#if DEBUG_PERSISTENCE
-    GE_LOG(ectx, 
-          GE_DEBUG | GE_REQUEST | GE_USER,
-          "NOT serializing FSUI state...\n");
-#endif
-    fd = -1;
+  /* 2) signal suspension events */
+  /* 2a) signal search suspension */
+  spos = ctx->activeSearches;
+  while (spos != NULL) {
+    event.type = FSUI_search_suspended;
+    event.data.SearchSuspended.sc.pos = spos;
+    event.data.SearchSuspended.sc.cctx = spos->cctx;
+    ctx->ecb(ctx->ecbClosure, &event);
+    spos = spos->next;
   }
-  if (fd != -1) {
-    if (ctx->collectionData == NULL) {
-      WRITEINT(fd, 0);
-    } else {
-      /* serialize collection data */
-      WRITE(fd,
-           ctx->collectionData,
-           ntohl(ctx->collectionData->size));
-    }
+  /* 2b) signal uploads suspension */
+  upos = ctx->activeUploads;
+  while (upos != NULL) {
+    event.type = FSUI_upload_suspended;
+    event.data.UploadSuspended.uc.pos = upos;
+    event.data.UploadSuspended.uc.cctx = upos->cctx;
+    event.data.UploadSuspended.uc.ppos = NULL; /* FIXME */
+    event.data.UploadSuspended.uc.pcctx = NULL; /* FIXME */
+    ctx->ecb(ctx->ecbClosure, &event);
+    upos = upos->next;
   }
+  /* 2c) signal downloads suspension */
+  signalDownloadSuspend(ectx,
+                       ctx,
+                       ctx->activeDownloads.child);
+  /* 2d) signal unindex suspension */
+  xpos = ctx->unindexOperations;
+  while (xpos != NULL) {
+    event.type = FSUI_unindex_suspended;
+    event.data.UnindexSuspended.uc.pos = xpos;
+    event.data.UnindexSuspended.uc.cctx = xpos->cctx;
+    xpos = xpos->next;    
+  }
+
+  /* 3) serialize all of the FSUI state */
+  if (ctx->ipc != NULL) 
+    FSUI_serialize(ctx);
+
+  /* 4) finally, free memory */
+  /* 4a) free search memory */
   while (ctx->activeSearches != NULL) {
     spos = ctx->activeSearches;
     ctx->activeSearches = spos->next;
-
-    spos->signalTerminate = YES;
-    PTHREAD_STOP_SLEEP(spos->handle);
-    PTHREAD_JOIN(spos->handle, &unused);
-    if (fd != -1) {
-      /* serialize pending searches */
-      char * tmp;
-      unsigned int big;
-
-      tmp = ECRS_uriToString(spos->uri);
-      GE_ASSERT(ectx, tmp != NULL);
-      big = htonl(strlen(tmp));
-      WRITE(fd,
-           &big,
-           sizeof(unsigned int));
-      WRITE(fd,
-           tmp,
-           strlen(tmp));
-      FREE(tmp);
-      big = htonl(spos->anonymityLevel);
-      WRITE(fd,
-           &big,
-           sizeof(unsigned int));
-      big = htonl(spos->sizeResultsReceived);
-      WRITE(fd,
-           &big,
-           sizeof(unsigned int));
-      big = htonl(spos->sizeUnmatchedResultsReceived);
-      WRITE(fd,
-           &big,
-           sizeof(unsigned int));
-      for (i=0;i<spos->sizeResultsReceived;i++)
-       writeFileInfo(ectx,
-                     fd,
-                     &spos->resultsReceived[i]);
-      for (i=0;i<spos->sizeUnmatchedResultsReceived;i++) {
-       ResultPending * rp;
-
-       rp = &spos->unmatchedResultsReceived[i];
-       writeFileInfo(ectx,
-                     fd,
-                     &rp->fi);
-       big = htonl(rp->matchingKeyCount);
-       WRITE(fd,
-             &big,
-             sizeof(unsigned int));
-       WRITE(fd,
-             rp->matchingKeys,
-             sizeof(HashCode512) * rp->matchingKeyCount);
-      }
-      event.type = FSUI_search_suspending;
-      event.data.SearchSuspending.sc.pos = spos;
-      event.data.SearchSuspending.sc.cctx = spos->cctx;
-      ctx->ecb(ctx->ecbClosure, &event);
-    }
-
-
     ECRS_freeUri(spos->uri);
     for (i=spos->sizeResultsReceived-1;i>=0;i--) {
       ECRS_FileInfo * fi;
@@ -927,7 +366,7 @@
         0);
     for (i=spos->sizeUnmatchedResultsReceived-1;i>=0;i--) {
       ResultPending * rp;
-
+      
       rp = &spos->unmatchedResultsReceived[i];
       GROW(rp->matchingKeys,
           rp->matchingKeyCount,
@@ -940,77 +379,17 @@
         0);
     FREE(spos);
   }
-  if (fd != -1) {
-    /* search list terminator */
-    big = htonl(0);
-    WRITE(fd,
-         &big,
-         sizeof(unsigned int));
-    writeDownloadList(ectx,
-                     fd,
-                     ctx,
-                     ctx->activeDownloads.child);
-  }
+  /* 4b) free unindex memory */
   while (ctx->unindexOperations != NULL) {
     xpos = ctx->unindexOperations;
     ctx->unindexOperations = xpos->next;
-    xpos->force_termination = YES;
-    PTHREAD_STOP_SLEEP(xpos->handle);
-    PTHREAD_JOIN(xpos->handle, &unused);    
-    if (fd != -1) {
-      WRITEINT(fd, strlen(xpos->filename));
-      WRITE(fd,
-           xpos->filename,
-           strlen(xpos->filename));
-      event.type = FSUI_unindex_suspending;
-      event.data.UnindexSuspending.uc.pos = xpos;
-      event.data.UnindexSuspending.uc.cctx = xpos->cctx;
-      ctx->ecb(ctx->ecbClosure, &event);
-    }
     FREE(xpos->filename);
+    FREE(xpos);
   }
-  if (fd != -1) {
-    /* unindex list terminator */
-    big = htonl(0);
-    WRITE(fd,
-         &big,
-         sizeof(unsigned int));
-  }
+  /* 4c) free upload memory */
   while (ctx->activeUploads != NULL) {
-    big = htonl(1);
-    WRITE(fd,
-         &big,
-         sizeof(unsigned int));
     upos = ctx->activeUploads;
     ctx->activeUploads = upos->next;
-    upos->force_termination = YES;
-    PTHREAD_STOP_SLEEP(upos->handle);
-    PTHREAD_JOIN(upos->handle, &unused);
-    if (fd != -1) {
-      WRITEINT(fd, upos->status);
-      WRITELONG(fd, upos->main_completed);
-      WRITELONG(fd, upos->main_total);
-      WRITELONG(fd, upos->expiration);
-      WRITELONG(fd, upos->start_time);
-      /* dir track!? */
-      writeURI(fd, upos->uri);
-      writeURI(fd, upos->globalUri); /* need to handle NULL? */
-      WRITESTRING(fd, upos->filename);
-      WRITESTRING(fd, upos->main_filename);
-      WRITEINT(fd, upos->isRecursive);
-      WRITEINT(fd, upos->doIndex);
-      WRITEINT(fd, upos->anonymityLevel);
-      WRITEINT(fd, upos->priority);
-      WRITEINT(fd, upos->individualKeywords);
-      
-
-      /* FIXME: serialize! */
-      event.type = FSUI_upload_suspending;
-      event.data.UploadSuspending.uc.pos = upos;
-      event.data.UploadSuspending.uc.cctx = upos->cctx;
-      event.data.UploadSuspending.uc.ppos = NULL;
-      event.data.UploadSuspending.uc.pcctx = NULL;
-    }
     FREE(upos->filename);
     FREENONNULL(upos->main_filename);
     ECRS_freeMetaData(upos->meta);
@@ -1020,26 +399,10 @@
     EXTRACTOR_removeAll(upos->extractors);
     FREE(upos);
   }
-  if (fd != -1) {
-    /* upload list terminator */
-    big = htonl(0);
-    WRITE(fd,
-         &big,
-         sizeof(unsigned int));
-  }
+  /* 4d) free download memory */
+  freeDownloadList(ctx->activeDownloads.child);
 
-  if (fd != -1) {
-#if DEBUG_PERSISTENCE
-    GE_LOG(ectx,
-          GE_DEBUG | GE_REQUEST | GE_USER,
-          "Serializing FSUI state done.\n");
-#endif
-    CLOSE(fd);
-  }
-
-  /* finally, free all (remaining) FSUI data */
-  while (ctx->activeDownloads.child != NULL)
-    freeDownloadList(ctx->activeDownloads.child);
+  /* 5) finish FSUI Context */
   if (ctx->ipc != NULL) {
     IPC_SEMAPHORE_UP(ctx->ipc);
     IPC_SEMAPHORE_DESTROY(ctx->ipc);
@@ -1054,39 +417,4 @@
 }
 
 
-/* *************** internal helper functions *********** */
-
-/**
- * The idea for this function is to clean up
- * the FSUI structs by freeing up dead entries.
- */
-void cleanupFSUIThreadList(FSUI_Context * ctx) {
-  FSUI_ThreadList * pos;
-  FSUI_ThreadList * tmp;
-  FSUI_ThreadList * prev;
-  void * unused;
-
-  prev = NULL;
-  MUTEX_LOCK(ctx->lock);
-  pos = ctx->activeThreads;
-  while (pos != NULL) {
-    if (YES == pos->isDone) {
-      PTHREAD_JOIN(pos->handle,
-                  &unused);
-      tmp = pos->next;
-      FREE(pos);
-      if (prev != NULL)
-       prev->next = tmp;
-      else
-       ctx->activeThreads = tmp;
-      pos = tmp;
-    } else {
-      prev = pos;
-      pos = pos->next;
-    }
-  }
-  MUTEX_UNLOCK(ctx->lock);
-}
-
-
 /* end of fsui.c */

Modified: GNUnet/src/applications/fs/fsui/fsui.h
===================================================================
--- GNUnet/src/applications/fs/fsui/fsui.h      2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/fsui.h      2006-10-13 03:09:42 UTC (rev 
3482)
@@ -20,7 +20,7 @@
 
 /**
  * @file applications/fs/fsui/fsui.h
- * @brief definition of the FSUI_Context
+ * @brief internal definitions for libfsui
  * @author Christian Grothoff
  */
 #ifndef FSUI_H
@@ -32,30 +32,62 @@
 #include "gnunet_blockstore.h"
 
 /**
- * Linked list of FSUI threads.
+ * Current state of a download (or uploads, or search,
+ * or unindex operations).
+ *
+ * PENDING means that the download is waiting for a thread
+ * to be assigned to run it.  Downloads start in this state,
+ * and during shutdown are serialized in this state.<br>
+ *
+ * ACTIVE means that there is currently a thread running
+ * the download (and that thread is allowed to continue).<br>
+ *
+ * COMPLETED means that the download is finished (but the
+ * thread has not been joined yet).  The download thread
+ * makes the transition from PENDING to COMPLETED when it
+ * is about to terminate.<br>
+ *
+ * COMPLETED_JOINED means that the download is finished and
+ * the thread has been joined.<br>
+ *
+ * ABORTED means that the user is causing the download to be
+ * terminated early (but the thread has not been joined yet).  The
+ * controller or the download thread make this transition; the
+ * download thread is supposed to terminate shortly after the state is
+ * moved to ABORTED.<br>
+ *
+ * ABORTED_JOINED means that the download did not complete
+ * successfully, should not be restarted and that the thread
+ * has been joined.<br>
+ *
+ * ERROR means that some fatal error is causing the download to be
+ * terminated early (but the thread has not been joined yet).  The
+ * controller or the download thread make this transition; the
+ * download thread is supposed to terminate shortly after the state is
+ * moved to ERROR.<br>
+ *
+ * ERROR_JOINED means that the download did not complete successfully,
+ * should not be restarted and that the thread has been joined.<br>
+ *
+ * SUSPENDING is used to notify the download thread that it
+ * should terminate because of an FSUI shutdown.  After this
+ * termination the code that joins the thread should move
+ * the state into PENDING (a new thread would not be started
+ * immediately because "threadPoolSize" will be 0 until FSUI
+ * resumes).
  */
-typedef struct FSUI_ThreadList {
+typedef enum {
+  FSUI_PENDING = 0,
+  FSUI_ACTIVE = 1,
+  FSUI_COMPLETED = 2,
+  FSUI_COMPLETED_JOINED = 3,
+  FSUI_ABORTED = 4,
+  FSUI_ABORTED_JOINED = 5,
+  FSUI_ERROR = 6,
+  FSUI_ERROR_JOINED = 7,
+  FSUI_SUSPENDING = 8,
+} FSUI_State;
 
-  /**
-   * FSUI threads are kept in a simple
-   * linked list
-   */
-  struct FSUI_ThreadList * next;
-
-  /**
-   * Handle to a thread.
-   */
-  struct PTHREAD * handle;
-
-  /**
-   * Flag that indicates if it is safe (i.e.
-   * non-blocking) to call join on the handle.
-   * Set to YES by an FSUI thread upon exit.
-   */
-  int isDone;
-
-} FSUI_ThreadList;
-
 /**
  * Track record for a given result.
  */
@@ -147,65 +179,6 @@
 } FSUI_SearchList;
 
 /**
- * Current state of a download (or uploads, or search,
- * or unindex operations).
- *
- * PENDING means that the download is waiting for a thread
- * to be assigned to run it.  Downloads start in this state,
- * and during shutdown are serialized in this state.<br>
- *
- * ACTIVE means that there is currently a thread running
- * the download (and that thread is allowed to continue).<br>
- *
- * COMPLETED means that the download is finished (but the
- * thread has not been joined yet).  The download thread
- * makes the transition from PENDING to COMPLETED when it
- * is about to terminate.<br>
- *
- * COMPLETED_JOINED means that the download is finished and
- * the thread has been joined.<br>
- *
- * ABORTED means that the user is causing the download to be
- * terminated early (but the thread has not been joined yet).  The
- * controller or the download thread make this transition; the
- * download thread is supposed to terminate shortly after the state is
- * moved to ABORTED.<br>
- *
- * ABORTED_JOINED means that the download did not complete
- * successfully, should not be restarted and that the thread
- * has been joined.<br>
- *
- * ERROR means that some fatal error is causing the download to be
- * terminated early (but the thread has not been joined yet).  The
- * controller or the download thread make this transition; the
- * download thread is supposed to terminate shortly after the state is
- * moved to ERROR.<br>
- *
- * ERROR_JOINED means that the download did not complete successfully,
- * should not be restarted and that the thread has been joined.<br>
- *
- * SUSPENDING is used to notify the download thread that it
- * should terminate because of an FSUI shutdown.  After this
- * termination the code that joins the thread should move
- * the state into PENDING (a new thread would not be started
- * immediately because "threadPoolSize" will be 0 until FSUI
- * resumes).
- */
-typedef enum {
-  FSUI_PENDING = 0,
-  FSUI_ACTIVE = 1,
-  FSUI_COMPLETED = 2,
-  FSUI_COMPLETED_JOINED = 3,
-  FSUI_ABORTED = 4,
-  FSUI_ABORTED_JOINED = 5,
-  FSUI_ERROR = 6,
-  FSUI_ERROR_JOINED = 7,
-  FSUI_SUSPENDING = 8,
-} FSUI_State;
-
-
-
-/**
  * @brief list of active downloads
  */
 typedef struct FSUI_DownloadList {
@@ -222,11 +195,6 @@
   unsigned long long completed;
 
   /**
-   * How many bytes have been retrieved so far for this particular file only.
-   */
-  unsigned long long completedFile;
-
-  /**
    * URI for this download.
    */
   struct ECRS_URI * uri;
@@ -278,11 +246,21 @@
   /**
    * When did the download start?  Note that if a download is resumed,
    * this time is set such that the total time is accurate, not the
-   * absolute start time.
+   * absolute start time.<p>
+   * While the download thread is running, this is the
+   * absolute start time assuming the thread ran continuously.
    */
   cron_t startTime;
 
   /**
+   * While the download thread is suspended, this is the
+   * total amount of time that all threads have consumed so far.
+   * While the download thread is running, startTime should
+   * be used instead (since runTime maybe outdated).
+   */
+  cron_t runTime;
+
+  /**
    * Is this a recursive download? (YES/NO)
    */
   int is_recursive;
@@ -355,6 +333,8 @@
 
 /**
  * Context for the upload thread.
+ *
+ * TODO: keep upload hierarchy!
  */
 typedef struct FSUI_UploadList {
 
@@ -448,12 +428,6 @@
   DataContainer * collectionData;
 
   /**
-   * Active FSUI threads that cannot be stopped and
-   * that FSUI must call join on before it may shutdown.
-   */
-  FSUI_ThreadList * activeThreads;
-
-  /**
    * List of active searches.
    */
   FSUI_SearchList * activeSearches;
@@ -485,6 +459,8 @@
 
 } FSUI_Context;
 
+/* ************ cross-file prototypes ************ */
+
 /**
  * Starts or stops download threads in accordance with thread pool
  * size and active downloads.  Call only while holding FSUI lock (or
@@ -492,31 +468,16 @@
  *
  * @return YES if change done that may require re-trying
  */
-int updateDownloadThread(FSUI_DownloadList * list);
+int FSUI_updateDownloadThread(FSUI_DownloadList * list);
 
-/**
- * Free the subtree (assumes all threads have already been stopped and
- * that the FSUI lock is either held or that we are in FSUI stop!).
- */
-void freeDownloadList(FSUI_DownloadList * list);
+void * FSUI_uploadThread(void * dl);
 
-/**
- * Cleanup the FSUI context (removes dead entries from
- * activeThreads / activeSearches / activeDownloads).
- */
-void cleanupFSUIThreadList(FSUI_Context * ctx);
+void * FSUI_searchThread(void * pos);
 
+void * FSUI_unindexThread(void * cls);
 
-/* FOR RESUME: from download.c */
-/**
- * Thread that downloads a file.
- */
-void * downloadThread(void * dl);
+void FSUI_serialize(struct FSUI_Context * ctx);
 
-/* from search.c */
-/**
- * FOR RESUME: Thread that searches for data.
- */
-void * searchThread(void /* FSUI_SearchList */ * pos);
+void FSUI_deserialize(struct FSUI_Context * ctx);
 
 #endif

Modified: GNUnet/src/applications/fs/fsui/search.c
===================================================================
--- GNUnet/src/applications/fs/fsui/search.c    2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/search.c    2006-10-13 03:09:42 UTC (rev 
3482)
@@ -240,7 +240,7 @@
 /**
  * Thread that searches for data.
  */
-void * searchThread(void * cls) {
+void * FSUI_searchThread(void * cls) {
   FSUI_SearchList * pos = cls;
   ECRS_search(pos->ctx->ectx,
              pos->ctx->cfg,
@@ -276,7 +276,7 @@
   pos->unmatchedResultsReceived = 0;
   pos->anonymityLevel = anonymityLevel;
   pos->ctx = ctx;
-  pos->handle = PTHREAD_CREATE(&searchThread,
+  pos->handle = PTHREAD_CREATE(&FSUI_searchThread,
                               pos,
                               32 * 1024);
   if (pos->handle == NULL) {

Added: GNUnet/src/applications/fs/fsui/serialize.c
===================================================================
--- GNUnet/src/applications/fs/fsui/serialize.c 2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/serialize.c 2006-10-13 03:09:42 UTC (rev 
3482)
@@ -0,0 +1,275 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2003, 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/serialize.c
+ * @brief FSUI functions for writing state to disk
+ * @author Christian Grothoff
+ * @see deserializer.c
+ *
+ * TODO:
+ * - upload tree handling (need to change upload representation)
+ */
+
+#include "platform.h"
+#include "gnunet_fsui_lib.h"
+#include "gnunet_directories.h"
+#include "fsui.h"
+
+static void WRITEINT(int fd,
+                    int val) {
+  int big;
+  big = htonl(val);
+  WRITE(fd, &big, sizeof(int));
+}
+
+static void WRITELONG(int fd,
+                     long long val) {
+  long long big;
+  big = htonll(val);
+  WRITE(fd, &big, sizeof(long long));
+}
+
+static void writeURI(int fd,
+                    const struct ECRS_URI * uri) {
+  char * buf;
+  unsigned int size;
+
+  buf = ECRS_uriToString(uri);
+  size = strlen(buf);
+  WRITEINT(fd, size);
+  WRITE(fd,
+       buf,
+       size);
+  FREE(buf);
+}
+
+static void WRITESTRING(int fd,
+                       const char * name) {
+  WRITEINT(fd,
+          strlen(name));
+  WRITE(fd,
+       name,
+       strlen(name));
+}
+
+/**
+ * (recursively) write a download list.
+ */
+static void writeDownloadList(struct GE_Context * ectx,
+                             int fd,
+                             FSUI_Context * ctx,
+                             FSUI_DownloadList * list) {
+  int i;
+
+  if (list == NULL) {
+    WRITEINT(fd, 0);
+    return;
+  }
+#if DEBUG_PERSISTENCE
+  GE_LOG(ectx,
+        GE_DEBUG | GE_REQUEST | GE_USER,
+        "Serializing download state of download `%s': (%llu, %llu)\n",
+        list->filename,
+        list->completed,
+        list->total);
+#endif
+  WRITEINT(fd, 1);
+  WRITEINT(fd, list->state);
+  WRITEINT(fd, list->is_recursive);
+  WRITEINT(fd, list->is_directory);
+  WRITEINT(fd, list->anonymityLevel);
+  WRITEINT(fd, list->completedDownloadsCount);
+  WRITELONG(fd, list->total);
+  WRITELONG(fd, list->completed);
+  WRITELONG(fd, get_time() - list->startTime);
+  WRITESTRING(fd, list->filename);
+  writeURI(fd, list->uri);
+  for (i=0;i<list->completedDownloadsCount;i++)
+    writeURI(fd, list->completedDownloads[i]);
+  writeDownloadList(ectx,
+                   fd,
+                   ctx,
+                   list->next);
+  writeDownloadList(ectx,
+                   fd,
+                   ctx,
+                   list->child);
+}
+
+
+static void writeFileInfo(struct GE_Context * ectx,
+                         int fd,
+                         const ECRS_FileInfo * fi) {
+  unsigned int size;
+  char * buf;
+
+  size = ECRS_sizeofMetaData(fi->meta,
+                            ECRS_SERIALIZE_FULL | ECRS_SERIALIZE_NO_COMPRESS);
+  if (size > 1024 * 1024)
+    size = 1024 * 1024;
+  buf = MALLOC(size);
+  ECRS_serializeMetaData(ectx,
+                        fi->meta,
+                        buf,
+                        size,
+                        ECRS_SERIALIZE_PART | ECRS_SERIALIZE_NO_COMPRESS);
+  WRITEINT(fd, size);
+  WRITE(fd,
+       buf,
+       size);
+  FREE(buf);
+  writeURI(fd, fi->uri);
+}
+
+static void writeCollection(int fd,
+                           struct FSUI_Context * ctx) {
+  if ( (ctx->collectionData == NULL) ||
+       (ctx->collectionData->size > 16 * 1024 * 1024) ) {
+    WRITEINT(fd, 0);
+    return;
+  }
+  /* serialize collection data */
+  WRITE(fd,
+       ctx->collectionData,
+       ntohl(ctx->collectionData->size));
+}
+
+static void writeSearches(int fd,
+                         struct FSUI_Context * ctx) {
+  char * tmp;
+  FSUI_SearchList * spos;
+  int i;
+
+  spos = ctx->activeSearches;
+  while (spos != NULL) {
+    if ( (spos->sizeResultsReceived > 1024 * 1024) ||
+        (spos->sizeUnmatchedResultsReceived > 1024 * 1024) ) {
+      /* too large to serialize - skip! */
+      spos = spos->next;
+      continue;
+    }
+    GE_ASSERT(ctx->ectx,
+             spos->signalTerminate == YES);
+    GE_ASSERT(ctx->ectx,
+             ECRS_isKeywordUri(spos->uri));
+    WRITEINT(fd, 1);
+    WRITEINT(fd, spos->state);
+    WRITEINT(fd, spos->anonymityLevel);
+    WRITEINT(fd, spos->sizeResultsReceived);
+    WRITEINT(fd, spos->sizeUnmatchedResultsReceived);
+    tmp = ECRS_uriToString(spos->uri);
+    GE_ASSERT(NULL, tmp != NULL);
+    WRITESTRING(fd, tmp);
+    FREE(tmp);
+    for (i=0;i<spos->sizeResultsReceived;i++)
+      writeFileInfo(ctx->ectx,
+                   fd,
+                   &spos->resultsReceived[i]);
+    for (i=0;i<spos->sizeUnmatchedResultsReceived;i++) {
+      ResultPending * rp;
+      
+      rp = &spos->unmatchedResultsReceived[i];
+      writeFileInfo(ctx->ectx,
+                   fd,
+                   &rp->fi);
+      GE_ASSERT(ctx->ectx,
+               rp->matchingKeyCount < spos->numberOfURIKeys);
+      if (rp->matchingKeyCount > 1024) {
+       WRITEINT(fd, 0); /* too large to serialize */
+       continue;
+      }
+      WRITEINT(fd, rp->matchingKeyCount);
+      WRITE(fd,
+           rp->matchingKeys,
+           sizeof(HashCode512) * rp->matchingKeyCount);
+    }
+    spos = spos->next;
+  }
+  WRITEINT(fd, 0);
+} 
+
+static void writeUnindexing(int fd,
+                           struct FSUI_Context * ctx) {
+  FSUI_UnindexList * xpos;
+
+
+  xpos = ctx->unindexOperations;
+  while (xpos != NULL) {
+    WRITEINT(fd, 1);
+    WRITEINT(fd, xpos->state);
+    WRITESTRING(fd, xpos->filename);
+    xpos = xpos->next;
+  }
+  /* unindex list terminator */
+  WRITEINT(fd, 0);
+}
+
+static void writeUploads(int fd,
+                        struct FSUI_Context * ctx) {
+  FSUI_UploadList * upos;
+
+  upos = ctx->activeUploads;
+  while (upos != NULL) {
+    WRITEINT(fd, 1);
+    WRITEINT(fd, upos->state);
+    WRITELONG(fd, upos->main_completed);
+    WRITELONG(fd, upos->main_total);
+    WRITELONG(fd, upos->expiration);
+    WRITELONG(fd, upos->start_time);
+    writeURI(fd, upos->uri);
+    writeURI(fd, upos->globalUri); /* need to handle NULL? */
+    WRITESTRING(fd, upos->filename);
+    WRITESTRING(fd, upos->main_filename);
+    WRITEINT(fd, upos->isRecursive);
+    WRITEINT(fd, upos->doIndex);
+    WRITEINT(fd, upos->anonymityLevel);
+    WRITEINT(fd, upos->priority);
+    WRITEINT(fd, upos->individualKeywords);
+    upos = upos->next;
+  }
+  WRITEINT(fd, 0);
+}
+
+void FSUI_serialize(struct FSUI_Context * ctx) {
+  int fd;
+
+  fd = disk_file_open(ctx->ectx,
+                     ctx->name,
+                     O_CREAT|O_TRUNC|O_WRONLY,
+                     S_IRUSR|S_IWUSR);
+  if (fd == -1) 
+    return;    
+  WRITE(fd,
+       "FSUI01\n\0",
+       8); /* magic */
+  writeCollection(fd, ctx);
+  writeSearches(fd, ctx);
+  writeDownloadList(ctx->ectx,
+                   fd,
+                   ctx,
+                   ctx->activeDownloads.child);
+  writeUnindexing(fd, ctx);
+  writeUploads(fd, ctx);  
+  CLOSE(fd);
+}
+
+/* end of serializer */


Property changes on: GNUnet/src/applications/fs/fsui/serialize.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: GNUnet/src/applications/fs/fsui/unindex.c
===================================================================
--- GNUnet/src/applications/fs/fsui/unindex.c   2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/unindex.c   2006-10-13 03:09:42 UTC (rev 
3482)
@@ -65,7 +65,7 @@
 /**
  * Thread that does the unindex.
  */
-static void * unindexThread(void * cls) {
+void * FSUI_unindexThread(void * cls) {
   FSUI_UnindexList * utc = cls;
   FSUI_Event event;
   int ret;
@@ -81,12 +81,12 @@
     event.type = FSUI_unindex_complete;
     if (OK != disk_file_size(utc->ctx->ectx,
                             utc->filename,
-                            &event.data.UnindexComplete.total,
+                            &event.data.UnindexCompleted.total,
                             YES)) {
       GE_BREAK(utc->ctx->ectx, 0);
-      event.data.UnindexComplete.total = 0;
+      event.data.UnindexCompleted.total = 0;
     }
-    event.data.UnindexComplete.filename = utc->filename;
+    event.data.UnindexCompleted.filename = utc->filename;
   } else {
     event.type = FSUI_unindex_error;
     event.data.UnindexError.message = _("Unindex failed.");
@@ -131,7 +131,7 @@
   utc->filename = STRDUP(filename);
   utc->start_time = get_time();
   utc->force_termination = NO;
-  utc->handle = PTHREAD_CREATE(&unindexThread,
+  utc->handle = PTHREAD_CREATE(&FSUI_unindexThread,
                               utc,
                               32 * 1024);
   if (utc->handle == NULL) {

Modified: GNUnet/src/applications/fs/fsui/upload.c
===================================================================
--- GNUnet/src/applications/fs/fsui/upload.c    2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/applications/fs/fsui/upload.c    2006-10-13 03:09:42 UTC (rev 
3482)
@@ -154,12 +154,11 @@
       if (ret == OK) {
        GE_ASSERT(ectx, NULL != *uri);
        event.type = FSUI_upload_complete;
-       event.data.UploadComplete.total = utc->main_total;
-       event.data.UploadComplete.filename = STRDUP(dirName);
-       event.data.UploadComplete.uri = *uri;
+       event.data.UploadCompleted.total = utc->main_total;
+       event.data.UploadCompleted.filename = dirName;
+       event.data.UploadCompleted.uri = *uri;
        utc->ctx->ecb(utc->ctx->ecbClosure,
                      &event);  
-       FREE(event.data.UploadComplete.filename);
        utc->main_completed += len;
       }
       UNLINK(tempName);
@@ -214,9 +213,9 @@
     if (ret == OK) {
       GE_ASSERT(ectx, uri != NULL);
       event.type = FSUI_upload_complete;
-      event.data.UploadComplete.total = utc->main_total;
-      event.data.UploadComplete.filename = utc->filename;
-      event.data.UploadComplete.uri = uri;
+      event.data.UploadCompleted.total = utc->main_total;
+      event.data.UploadCompleted.filename = utc->filename;
+      event.data.UploadCompleted.uri = uri;
       if (OK == disk_file_size(ectx, 
                               fn, 
                               &len,
@@ -332,7 +331,7 @@
 /**
  * Thread that does the upload.
  */
-static void * uploadThread(void * cls) {
+void * FSUI_uploadThread(void * cls) {
   FSUI_UploadList * utc = cls;
   struct ECRS_URI * uri;
   struct ECRS_URI * keywordUri;
@@ -378,9 +377,9 @@
                          &uri);
     if (ret == OK) {
       event.type = FSUI_upload_complete;
-      event.data.UploadComplete.total = utc->main_total;
-      event.data.UploadComplete.filename = utc->filename;
-      event.data.UploadComplete.uri = uri;
+      event.data.UploadCompleted.total = utc->main_total;
+      event.data.UploadCompleted.filename = utc->filename;
+      event.data.UploadCompleted.uri = uri;
     } else {
       event.type = FSUI_upload_error;
       event.data.UploadError.message = _("Upload failed.");
@@ -556,7 +555,7 @@
   utc->doIndex = doIndex;
   utc->individualKeywords = NO;
   utc->force_termination = NO;
-  utc->handle = PTHREAD_CREATE(&uploadThread,
+  utc->handle = PTHREAD_CREATE(&FSUI_uploadThread,
                               utc,
                               128 * 1024);
   if (utc->handle == NULL) {
@@ -575,7 +574,6 @@
   utc->next = ctx->activeUploads;
   ctx->activeUploads = utc;
   MUTEX_UNLOCK(ctx->lock);
-  cleanupFSUIThreadList(ctx);
   return utc;
 }
 

Modified: GNUnet/src/applications/fs/tools/gnunet-download.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-download.c  2006-10-12 20:51:47 UTC 
(rev 3481)
+++ GNUnet/src/applications/fs/tools/gnunet-download.c  2006-10-13 03:09:42 UTC 
(rev 3482)
@@ -25,6 +25,7 @@
  */
 
 #include "platform.h"
+#include "gnunet_directories.h"
 #include "gnunet_fsui_lib.h"
 #include "gnunet_util_config_impl.h"
 #include "gnunet_util_error_loggers.h"
@@ -37,14 +38,12 @@
 
 static int do_recursive;
 
-static char * cfgFilename;
+static char * cfgFilename = DEFAULT_CLIENT_CONFIG_FILE;
 
 static char * filename;
 
 static unsigned int anonymity = 1;
 
-static struct SEMAPHORE * signalFinished;
-
 static cron_t start_time;
 
 static struct FSUI_DownloadList * dl;
@@ -96,21 +95,14 @@
   case FSUI_download_aborted:
     if (dl == event->data.DownloadError.dc.pos) {
       /* top-download aborted */
-      PRINTF(_("Error downloading: %s\n"),
-            event->data.DownloadError.message);
-      *ok = SYSERR;
-      SEMAPHORE_UP(signalFinished);
-    } else {
-      /* child aborted, maybe FSUI thread
-        policy, ignore?  How can this
-        happen anyway with gnunet-download? */
+      PRINTF(_("Download aborted.\n"));
     }
     break;
   case FSUI_download_error:
     printf(_("Error downloading: %s\n"),
           event->data.DownloadError.message);
     *ok = SYSERR;
-    SEMAPHORE_UP(signalFinished);
+    GNUNET_SHUTDOWN_INITIATE();
     break;
   case FSUI_download_complete:
     if ( (event->data.DownloadProgress.completed ==
@@ -123,7 +115,7 @@
              / (double)cronSECONDS) );
       if (dl == event->data.DownloadProgress.dc.pos) {
        *ok = OK;
-       SEMAPHORE_UP(signalFinished);
+       GNUNET_SHUTDOWN_INITIATE();
       }
     }
     break;
@@ -164,12 +156,13 @@
                           gnunetdownloadOptions,
                           (unsigned int) argc,
                           argv);
-  if (i == SYSERR) {
+  if ( (i == SYSERR) ||
+       (0 != GC_parse_configuration(cfg,
+                                   cfgFilename)) ) {    
     GC_free(cfg);
     GE_free_context(ectx);
     return -1;  
   }
-
   if (i == argc) {
     GE_LOG(ectx,
           GE_WARNING | GE_BULK | GE_USER,
@@ -215,7 +208,7 @@
           filename);
     try_rename = YES;
   }
-  signalFinished = SEMAPHORE_CREATE(0);
+  ok = NO;
   ctx = FSUI_start(ectx,
                   cfg,
                   "gnunet-download",
@@ -229,14 +222,14 @@
                          do_recursive,
                          uri,
                          filename);
-  /* FIXME: use gnunetutil shutdown management instead! */
-  if (dl != NULL)
-    SEMAPHORE_DOWN(signalFinished, YES);
+  GNUNET_SHUTDOWN_WAITFOR();
+  if (OK != ok)
+    FSUI_abortDownload(ctx, dl);
   FSUI_stopDownload(ctx, dl);
   FSUI_stop(ctx);
-  SEMAPHORE_DESTROY(signalFinished);
 
-  if ( (dl != NULL) &&
+  if ( (OK == ok) &&
+       (dl != NULL) &&
        (try_rename == YES) ) {
     char * newname = ECRS_suggestFilename(ectx,
                                          filename);
@@ -252,7 +245,7 @@
   ECRS_freeUri(uri);
   GC_free(cfg);
   GE_free_context(ectx);
-  if (dl == NULL)
+  if (ok != OK)
     return 1;
   return 0;
 }

Modified: GNUnet/src/applications/fs/tools/gnunet-insert.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-insert.c    2006-10-12 20:51:47 UTC 
(rev 3481)
+++ GNUnet/src/applications/fs/tools/gnunet-insert.c    2006-10-13 03:09:42 UTC 
(rev 3482)
@@ -177,21 +177,21 @@
       delta = get_time() - start_time;
       PRINTF(_("Upload of `%s' complete, "
               "%llu bytes took %llu seconds (%8.3f KiB/s).\n"),
-            event->data.UploadComplete.filename,
-            event->data.UploadComplete.total,
+            event->data.UploadCompleted.filename,
+            event->data.UploadCompleted.total,
             delta / cronSECONDS,
             (delta == 0)
             ? (double) (-1.0)
-            : (double) (event->data.UploadComplete.total
+            : (double) (event->data.UploadCompleted.total
                         / 1024.0 * cronSECONDS / delta));
     }
-    fstring = ECRS_uriToString(event->data.UploadComplete.uri);        
+    fstring = ECRS_uriToString(event->data.UploadCompleted.uri);       
     printf(_("File `%s' has URI: %s\n"),
-          event->data.UploadComplete.filename,
+          event->data.UploadCompleted.filename,
           fstring);
     FREE(fstring);
-    if (ul == event->data.UploadComplete.uc.pos) {
-      postProcess(event->data.UploadComplete.uri);
+    if (ul == event->data.UploadCompleted.uc.pos) {
+      postProcess(event->data.UploadCompleted.uri);
       if (exitSignal != NULL)
        SEMAPHORE_UP(exitSignal);
     }

Modified: GNUnet/src/applications/fs/tools/gnunet-unindex.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-unindex.c   2006-10-12 20:51:47 UTC 
(rev 3481)
+++ GNUnet/src/applications/fs/tools/gnunet-unindex.c   2006-10-13 03:09:42 UTC 
(rev 3482)
@@ -70,12 +70,12 @@
       delta = get_time() - start_time;
       PRINTF(
       _("\nUnindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f 
KiB/s).\n"),
-      event->data.UnindexComplete.filename,
-      event->data.UnindexComplete.total,
+      event->data.UnindexCompleted.filename,
+      event->data.UnindexCompleted.total,
       delta / cronSECONDS,
       (delta == 0)
       ? (double) (-1.0)
-      : (double) (event->data.UnindexComplete.total / 1024.0 * cronSECONDS / 
delta));
+      : (double) (event->data.UnindexCompleted.total / 1024.0 * cronSECONDS / 
delta));
     }
     SEMAPHORE_UP(exitSignal);
     break;

Modified: GNUnet/src/include/gnunet_fsui_lib.h
===================================================================
--- GNUnet/src/include/gnunet_fsui_lib.h        2006-10-12 20:51:47 UTC (rev 
3481)
+++ GNUnet/src/include/gnunet_fsui_lib.h        2006-10-13 03:09:42 UTC (rev 
3482)
@@ -31,15 +31,17 @@
  * event processor also may have to worry about synchronizing itself
  * with the GUI library to display updates).<p>
  *
- * After creating a FSUI_Context with FSUI_start the UI can start (or
- * cancel) uploads, downloads or searches.  The FSUI_Context can be
- * destroyed, when it is created again the next time all pending
- * operations are resumed (!).  Clients can use the various iterator
- * functions to obtain information about pending actions.<p>
+ * After creating a FSUI_Context with FSUI_start the UI can start,
+ * abort and stop uploads, downloads, deletions or searches. 
+ * The FSUI_Context can be destroyed, when it is created again
+ * the next time all pending operations are resumed (!).
+ * Clients can use the various iterator functions to obtain
+ * information about pending actions.<p>
  *
- * Note that there can only be one FSUI_Context for all clients.
+ * Note that there can only be one FSUI_Context for a given
+ * client application name if resuming is enabled.
  * Creating an FSUI_Context may _fail_ if any other UI is currently
- * running (for the same user).<p>
+ * running (for the same user and application name).<p>
  *
  * Clients may use SOME functions of GNUnet's ECRS library, in
  * particular functions to deal with URIs and MetaData, but generally
@@ -54,8 +56,20 @@
  * unindexing operations have completed before attempting to close
  * the FSUI_Context.<p>
  *
+ * Any "startXXX" operation will result in FSUI state and memory
+ * being allocated until it is paired with a "stopXXX" operation.
+ * Before calling "stopXXX", one of three things must happen:
+ * Either, the client receives an "error" (something went wrong)
+ * or "completed" (action finished) event.  Alternatively, the
+ * client may call abortXXX" which will result in an "aborted"
+ * event.  In either case, the event itself will NOT result in 
+ * the action being "forgotten" by FSUI -- the client must still
+ * call "FSUI_stopXXX" explicitly.  Clients that call 
+ * "FSUI_stopXXX" before an aborted, error or completed event
+ * will be blocked until either of the three events happens.<p>
+ *
  * Note that most of this code is completely new in GNUnet 0.7.0 and
- * thus still highly experimental.  Suggestions are welcome.
+ * thus still highly experimental.  Suggestions are welcome.<p>
  */
 
 #ifndef GNUNET_FSUI_LIB_H
@@ -95,7 +109,8 @@
  * 
  * For the types aborted, error, suspending and complete,
  * the client MUST free the "cctx" context associated with
- * the event (if allocated).<p>
+ * the event (if allocated).  This context is created
+ * by the "resume" operation.<p>
  *
  * Resume events are issued when operations resume as well
  * as when they are first initiated!<p>
@@ -104,31 +119,38 @@
  * number of results has been found.
  */
 enum FSUI_EventType {
-
+  FSUI_search_started,
+  FSUI_search_stopped,
   FSUI_search_result,
   FSUI_search_completed,
   FSUI_search_aborted,
   FSUI_search_error,
-  FSUI_search_suspending,
-  FSUI_search_resuming,
+  FSUI_search_suspended,
+  FSUI_search_resumed,
+  FSUI_download_started,
+  FSUI_download_stopped,
   FSUI_download_progress,
   FSUI_download_complete,
   FSUI_download_aborted,
   FSUI_download_error,
-  FSUI_download_suspending,
-  FSUI_download_resuming,
+  FSUI_download_suspended,
+  FSUI_download_resumed,
+  FSUI_upload_started,
+  FSUI_upload_stopped,
   FSUI_upload_progress,
   FSUI_upload_complete,
   FSUI_upload_aborted,
   FSUI_upload_error,
-  FSUI_upload_suspending,
-  FSUI_upload_resuming,
+  FSUI_upload_suspended,
+  FSUI_upload_resumed,
+  FSUI_unindex_started,
+  FSUI_unindex_stopped,
   FSUI_unindex_progress,
   FSUI_unindex_complete,
   FSUI_unindex_aborted,
   FSUI_unindex_error,
-  FSUI_unindex_suspending,
-  FSUI_unindex_resuming,
+  FSUI_unindex_suspended,
+  FSUI_unindex_resumed,
   /**
    * Connection status with gnunetd changed.
    */
@@ -223,55 +245,69 @@
        * The URI of the search for which data was
        * found.
        */
-      struct ECRS_URI * searchURI;
+      const struct ECRS_URI * searchURI;
 
     } SearchResult;
 
 
     struct {
 
-      struct FSUI_SearchList * pos;
+      FSUI_SearchContext sc;
 
     } SearchCompleted;
 
     struct {
 
-      struct FSUI_SearchList * pos;
+      FSUI_SearchContext sc;
 
     } SearchAborted;
 
-
     struct {
 
       FSUI_SearchContext sc;
+      
+      const char * message;
 
-      char * message;
-
     } SearchError;
 
+    struct {
 
+      FSUI_SearchContext sc;
+
+    } SearchSuspended;
+
     struct {
 
       FSUI_SearchContext sc;
 
-    } SearchSuspending;
+      struct ECRS_URI * searchURI;
 
+      const ECRS_FileInfo * fis;
 
+      unsigned int anonymityLevel;
+
+      unsigned int fisSize;
+
+    } SearchResumed;
+
     struct {
 
       FSUI_SearchContext sc;
 
-      ECRS_FileInfo * fis;
+      const struct ECRS_URI * searchURI;
 
-      unsigned int fisSize;
-
       unsigned int anonymityLevel;
 
-      struct ECRS_URI * searchURI;
+    } SearchStarted;
 
-    } SearchResuming;
+    struct {
 
+      FSUI_SearchContext sc;
+      
+    } SearchStopped;
 
+
+
     struct {
 
       FSUI_DownloadContext dc;
@@ -300,12 +336,12 @@
       /**
        * Information about the download.
        */
-      char * filename;
+      const char * filename;
 
       /**
        * Original URI.
        */
-      struct ECRS_URI * uri;
+      const struct ECRS_URI * uri;
 
       /**
        * The last block (in plaintext)
@@ -333,14 +369,14 @@
       /**
        * Information about the download.
        */
-      char * filename;
+      const char * filename;
 
       /**
        * Original URI.
        */
-      struct ECRS_URI * uri;
+      const struct ECRS_URI * uri;
 
-    } DownloadComplete;
+    } DownloadCompleted;
 
 
     struct {
@@ -366,14 +402,45 @@
 
       FSUI_DownloadContext dc;
 
-    } DownloadSuspending;
+    } DownloadStopped;
 
 
     struct {
 
       FSUI_DownloadContext dc;
 
+    } DownloadSuspended;
+
+
+    struct {
+
+      FSUI_DownloadContext dc;
+
       /**
+       * How large is the total download (as far
+       * as known so far).
+       */
+      unsigned long long total;
+
+      /**
+       * Information about the download.
+       */
+      const char * filename;
+
+      /**
+       * Original URI.
+       */
+      const struct ECRS_URI * uri;
+
+      unsigned int anonymityLevel;
+
+    } DownloadStarted;
+
+    struct {
+
+      FSUI_DownloadContext dc;
+
+      /**
        * How far are we?
        */
       unsigned long long completed;
@@ -392,18 +459,18 @@
       /**
        * Information about the download.
        */
-      char * filename;
+      const char * filename;
 
-      unsigned int anonymityLevel;
-
       /**
        * Original URI.
        */
-      struct ECRS_URI * uri;
+      const struct ECRS_URI * uri;
 
-    } DownloadResuming;
+      unsigned int anonymityLevel;
 
+    } DownloadResumed;
 
+
     struct {
 
       FSUI_UploadContext uc;
@@ -426,7 +493,7 @@
       /**
        * Information about the upload.
        */
-      char * filename;
+      const char * filename;
 
     } UploadProgress;
 
@@ -443,14 +510,14 @@
       /**
        * Which file was uploaded?
        */
-      char * filename;
+      const char * filename;
 
       /**
        * URI of the uploaded file.
        */
       struct ECRS_URI * uri;
 
-    } UploadComplete;
+    } UploadCompleted;
 
 
     struct {
@@ -464,16 +531,21 @@
 
       FSUI_UploadContext uc;
 
-      char * message;
+      const char * message;
 
     } UploadError;
 
+    struct {
 
+      FSUI_UploadContext uc;
+
+    } UploadSuspended;
+
     struct {
 
       FSUI_UploadContext uc;
 
-    } UploadSuspending;
+    } UploadStopped;
 
 
     struct {
@@ -481,6 +553,24 @@
       FSUI_UploadContext uc;
 
       /**
+       * How large is the total upload (for the current file)
+       */
+      unsigned long long total;
+
+      unsigned int anonymityLevel;
+
+      /**
+       * Information about the upload.
+       */
+      const char * filename;
+
+    } UploadStarted;
+
+    struct {
+
+      FSUI_UploadContext uc;
+
+      /**
        * How far are we? (for the current file)
        */
       unsigned long long completed;
@@ -500,9 +590,9 @@
       /**
        * Information about the upload.
        */
-      char * filename;
+      const char * filename;
 
-    } UploadResuming;
+    } UploadResumed;
 
 
     struct {
@@ -515,7 +605,7 @@
 
       cron_t eta;
 
-      char * filename;
+      const char * filename;
 
     } UnindexProgress;
 
@@ -526,9 +616,9 @@
 
       unsigned long long total;
 
-      char * filename;
+      const char * filename;
 
-    } UnindexComplete;
+    } UnindexCompleted;
 
 
     struct {
@@ -537,12 +627,18 @@
 
     } UnindexAborted;
 
+    struct {
 
+      FSUI_UnindexContext uc;
+
+    } UnindexStopped;
+
+
     struct {
 
       FSUI_UnindexContext uc;
 
-    } UnindexSuspending;
+    } UnindexSuspended;
 
 
     struct {
@@ -554,18 +650,28 @@
       unsigned long long completed;
 
       cron_t eta;
+      
+      const char * filename;
 
-      char * filename;
+    } UnindexResumed;
 
-    } UnindexResuming;
+    struct {
 
+      FSUI_UnindexContext uc;
+      
+      unsigned long long total;
+      
+      const char * filename;
 
+    } UnindexStarted;
+
+
     struct {
 
       FSUI_UnindexContext uc;
+      
+      const char * message;
 
-      char * message;
-
     } UnindexError;    
 
   } data;
@@ -651,6 +757,14 @@
                 const struct ECRS_URI * uri); /* search.c */
 
 /**
+ * Abort a search.
+ *
+ * @return SYSERR if such a search is not known
+ */
+int FSUI_abortSearch(struct FSUI_Context * ctx,
+                    struct FSUI_SearchList * sl); /* search.c */
+
+/**
  * Stop a search.
  *
  * @return SYSERR if such a search is not known
@@ -676,6 +790,15 @@
  *
  * @return SYSERR on error
  */
+int FSUI_abortDownload(struct FSUI_Context * ctx,
+                      struct FSUI_DownloadList * dl); /* download.c */
+
+/**
+ * Stop a download.  If the dl is for a recursive
+ * download, all sub-downloads will also be stopped.
+ *
+ * @return SYSERR on error
+ */
 int FSUI_stopDownload(struct FSUI_Context * ctx,
                      struct FSUI_DownloadList * dl); /* download.c */
 
@@ -712,6 +835,15 @@
  *
  * @return SYSERR on error
  */
+int FSUI_abortUpload(struct FSUI_Context * ctx,
+                    struct FSUI_UploadList * ul);
+
+/**
+ * Stop an upload.  If the context is for a recursive
+ * upload, all sub-uploads will also be stopped.
+ *
+ * @return SYSERR on error
+ */
 int FSUI_stopUpload(struct FSUI_Context * ctx,
                    struct FSUI_UploadList * ul);
 
@@ -733,6 +865,16 @@
  *
  * @return SYSERR on error
  */
+int FSUI_abortUnindex(struct FSUI_Context * ctx,
+                     struct FSUI_UnindexList * ul);
+
+
+/**
+ * Stop an unindex operation.  If the context is for a recursive
+ * upload, all sub-uploads will also be stopped.
+ *
+ * @return SYSERR on error
+ */
 int FSUI_stopUnindex(struct FSUI_Context * ctx,
                     struct FSUI_UnindexList * ul);
 





reply via email to

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