Forget to commit some files
[oweals/gnunet.git] / src / fs / fs_dirmetascan.c
index 9ee69c860437e0955d4a3b3edbeea274c708f2ab..45d502c91859552f33206d4cedbee218338cfb45 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet
 /*
      This file is part of GNUnet
-     (C) 2005-2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2005-2012 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
 
      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
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      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.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
 */
 
 /**
@@ -53,13 +53,13 @@ struct GNUNET_FS_DirScanner
    * Second argument to helper process.
    */
   char *ex_arg;
    * Second argument to helper process.
    */
   char *ex_arg;
-  
+
   /**
    * The function that will be called every time there's a progress
    * message.
    */
   GNUNET_FS_DirScannerProgressCallback progress_callback;
   /**
    * The function that will be called every time there's a progress
    * message.
    */
   GNUNET_FS_DirScannerProgressCallback progress_callback;
-  
+
   /**
    * A closure for progress_callback.
    */
   /**
    * A closure for progress_callback.
    */
@@ -68,7 +68,7 @@ struct GNUNET_FS_DirScanner
   /**
    * After the scan is finished, it will contain a pointer to the
    * top-level directory entry in the directory tree built by the
   /**
    * After the scan is finished, it will contain a pointer to the
    * top-level directory entry in the directory tree built by the
-   * scanner. 
+   * scanner.
    */
   struct GNUNET_FS_ShareTreeItem *toplevel;
 
    */
   struct GNUNET_FS_ShareTreeItem *toplevel;
 
@@ -77,6 +77,11 @@ struct GNUNET_FS_DirScanner
    */
   struct GNUNET_FS_ShareTreeItem *pos;
 
    */
   struct GNUNET_FS_ShareTreeItem *pos;
 
+  /**
+   * Task scheduled when we are done.
+   */
+  struct GNUNET_SCHEDULER_Task * stop_task;
+
   /**
    * Arguments for helper.
    */
   /**
    * Arguments for helper.
    */
@@ -85,9 +90,9 @@ struct GNUNET_FS_DirScanner
 };
 
 
 };
 
 
-
 /**
 /**
- * Abort the scan.
+ * Abort the scan.  Must not be called from within the progress_callback
+ * function.
  *
  * @param ds directory scanner structure
  */
  *
  * @param ds directory scanner structure
  */
@@ -96,11 +101,13 @@ GNUNET_FS_directory_scan_abort (struct GNUNET_FS_DirScanner *ds)
 {
   /* terminate helper */
   if (NULL != ds->helper)
 {
   /* terminate helper */
   if (NULL != ds->helper)
-    GNUNET_HELPER_stop (ds->helper);
-  
+    GNUNET_HELPER_stop (ds->helper, GNUNET_NO);
+
   /* free resources */
   if (NULL != ds->toplevel)
     GNUNET_FS_share_tree_free (ds->toplevel);
   /* free resources */
   if (NULL != ds->toplevel)
     GNUNET_FS_share_tree_free (ds->toplevel);
+  if (NULL != ds->stop_task)
+    GNUNET_SCHEDULER_cancel (ds->stop_task);
   GNUNET_free_non_null (ds->ex_arg);
   GNUNET_free (ds->filename_expanded);
   GNUNET_free (ds);
   GNUNET_free_non_null (ds->ex_arg);
   GNUNET_free (ds->filename_expanded);
   GNUNET_free (ds);
@@ -124,7 +131,7 @@ GNUNET_FS_directory_scan_get_result (struct GNUNET_FS_DirScanner *ds)
   GNUNET_assert (NULL == ds->helper);
   /* preserve result */
   result = ds->toplevel;
   GNUNET_assert (NULL == ds->helper);
   /* preserve result */
   result = ds->toplevel;
-  ds->toplevel = NULL; 
+  ds->toplevel = NULL;
   GNUNET_FS_directory_scan_abort (ds);
   return result;
 }
   GNUNET_FS_directory_scan_abort (ds);
   return result;
 }
@@ -141,10 +148,10 @@ static struct GNUNET_FS_ShareTreeItem *
 advance (struct GNUNET_FS_ShareTreeItem *pos)
 {
   int moved;
 advance (struct GNUNET_FS_ShareTreeItem *pos)
 {
   int moved;
-  
+
   GNUNET_assert (NULL != pos);
   moved = 0; /* must not terminate, even on file, otherwise "normal" */
   GNUNET_assert (NULL != pos);
   moved = 0; /* must not terminate, even on file, otherwise "normal" */
-  while ( (pos->is_directory) ||
+  while ( (pos->is_directory == GNUNET_YES) ||
          (0 == moved) )
   {
     if ( (moved != -1) &&
          (0 == moved) )
   {
     if ( (moved != -1) &&
@@ -187,20 +194,54 @@ expand_tree (struct GNUNET_FS_ShareTreeItem *parent,
             int is_directory)
 {
   struct GNUNET_FS_ShareTreeItem *chld;
             int is_directory)
 {
   struct GNUNET_FS_ShareTreeItem *chld;
+  size_t slen;
 
 
-  chld = GNUNET_malloc (sizeof (struct GNUNET_FS_ShareTreeItem));
+  chld = GNUNET_new (struct GNUNET_FS_ShareTreeItem);
   chld->parent = parent;
   chld->filename = GNUNET_strdup (filename);
   chld->parent = parent;
   chld->filename = GNUNET_strdup (filename);
-  chld->short_filename = GNUNET_strdup (GNUNET_STRINGS_get_short_name (filename));
+  GNUNET_asprintf (&chld->short_filename,
+                  "%s%s",
+                  GNUNET_STRINGS_get_short_name (filename),
+                  is_directory == GNUNET_YES ? "/" : "");
+  /* make sure we do not end with '//' */
+  slen = strlen (chld->short_filename);
+  if ( (slen >= 2) &&
+       (chld->short_filename[slen-1] == '/') &&
+       (chld->short_filename[slen-2] == '/') )
+    chld->short_filename[slen-1] = '\0';
   chld->is_directory = is_directory;
   if (NULL != parent)
       GNUNET_CONTAINER_DLL_insert (parent->children_head,
                                   parent->children_tail,
   chld->is_directory = is_directory;
   if (NULL != parent)
       GNUNET_CONTAINER_DLL_insert (parent->children_head,
                                   parent->children_tail,
-                                  chld);  
+                                  chld);
   return chld;
 }
 
 
   return chld;
 }
 
 
+/**
+ * Task run last to shut everything down.
+ *
+ * @param cls the 'struct GNUNET_FS_DirScanner'
+ * @param tc unused
+ */
+static void
+finish_scan (void *cls,
+            const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_FS_DirScanner *ds = cls;
+
+  ds->stop_task = NULL;
+  if (NULL != ds->helper)
+  {
+    GNUNET_HELPER_stop (ds->helper, GNUNET_NO);
+    ds->helper = NULL;
+  }
+  ds->progress_callback (ds->progress_callback_cls,
+                        NULL, GNUNET_SYSERR,
+                        GNUNET_FS_DIRSCANNER_FINISHED);
+}
+
+
 /**
  * Called every time there is data to read from the scanner.
  * Calls the scanner progress handler.
 /**
  * Called every time there is data to read from the scanner.
  * Calls the scanner progress handler.
@@ -209,8 +250,8 @@ expand_tree (struct GNUNET_FS_ShareTreeItem *parent,
  * @param client always NULL
  * @param msg message from the helper process
  */
  * @param client always NULL
  * @param msg message from the helper process
  */
-static void
-process_helper_msgs (void *cls, 
+static int
+process_helper_msgs (void *cls,
                     void *client,
                     const struct GNUNET_MessageHeader *msg)
 {
                     void *client,
                     const struct GNUNET_MessageHeader *msg)
 {
@@ -218,6 +259,11 @@ process_helper_msgs (void *cls,
   const char *filename;
   size_t left;
 
   const char *filename;
   size_t left;
 
+#if 0
+  fprintf (stderr, "DMS parses %u-byte message of type %u\n",
+          (unsigned int) ntohs (msg->size),
+          (unsigned int) ntohs (msg->type));
+#endif
   left = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader);
   filename = (const char*) &msg[1];
   switch (ntohs (msg->type))
   left = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader);
   filename = (const char*) &msg[1];
   switch (ntohs (msg->type))
@@ -228,7 +274,7 @@ process_helper_msgs (void *cls,
       GNUNET_break (0);
       break;
     }
       GNUNET_break (0);
       break;
     }
-    ds->progress_callback (ds->progress_callback_cls, 
+    ds->progress_callback (ds->progress_callback_cls,
                           filename, GNUNET_NO,
                           GNUNET_FS_DIRSCANNER_FILE_START);
     if (NULL == ds->toplevel)
                           filename, GNUNET_NO,
                           GNUNET_FS_DIRSCANNER_FILE_START);
     if (NULL == ds->toplevel)
@@ -237,7 +283,7 @@ process_helper_msgs (void *cls,
     else
       (void) expand_tree (ds->pos,
                          filename, GNUNET_NO);
     else
       (void) expand_tree (ds->pos,
                          filename, GNUNET_NO);
-    return;
+    return GNUNET_OK;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY:
     if (filename[left-1] != '\0')
     {
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY:
     if (filename[left-1] != '\0')
     {
@@ -252,25 +298,25 @@ process_helper_msgs (void *cls,
        break;
       }
       ds->pos = ds->pos->parent;
        break;
       }
       ds->pos = ds->pos->parent;
-      return;
+      return GNUNET_OK;
     }
     }
-    ds->progress_callback (ds->progress_callback_cls, 
+    ds->progress_callback (ds->progress_callback_cls,
                           filename, GNUNET_YES,
                           GNUNET_FS_DIRSCANNER_FILE_START);
     ds->pos = expand_tree (ds->pos,
                           filename, GNUNET_YES);
     if (NULL == ds->toplevel)
       ds->toplevel = ds->pos;
                           filename, GNUNET_YES,
                           GNUNET_FS_DIRSCANNER_FILE_START);
     ds->pos = expand_tree (ds->pos,
                           filename, GNUNET_YES);
     if (NULL == ds->toplevel)
       ds->toplevel = ds->pos;
-    return;
+    return GNUNET_OK;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR:
     break;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE:
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR:
     break;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE:
-    if (filename[left-1] != '\0')
+    if ('\0' != filename[left-1])
       break;
       break;
-    ds->progress_callback (ds->progress_callback_cls, 
+    ds->progress_callback (ds->progress_callback_cls,
                           filename, GNUNET_SYSERR,
                           GNUNET_FS_DIRSCANNER_FILE_IGNORED);
                           filename, GNUNET_SYSERR,
                           GNUNET_FS_DIRSCANNER_FILE_IGNORED);
-    return;
+    return GNUNET_OK;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE:
     if (0 != left)
     {
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE:
     if (0 != left)
     {
@@ -282,18 +328,18 @@ process_helper_msgs (void *cls,
       GNUNET_break (0);
       break;
     }
       GNUNET_break (0);
       break;
     }
-    ds->progress_callback (ds->progress_callback_cls, 
+    ds->progress_callback (ds->progress_callback_cls,
                           NULL, GNUNET_SYSERR,
                           GNUNET_FS_DIRSCANNER_ALL_COUNTED);
     ds->pos = ds->toplevel;
                           NULL, GNUNET_SYSERR,
                           GNUNET_FS_DIRSCANNER_ALL_COUNTED);
     ds->pos = ds->toplevel;
-    if (ds->pos->is_directory)
+    if (GNUNET_YES == ds->pos->is_directory)
       ds->pos = advance (ds->pos);
       ds->pos = advance (ds->pos);
-    return;
+    return GNUNET_OK;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA:
     {
       size_t nlen;
       const char *end;
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA:
     {
       size_t nlen;
       const char *end;
-      
+
       if (NULL == ds->pos)
       {
        GNUNET_break (0);
       if (NULL == ds->pos)
       {
        GNUNET_break (0);
@@ -314,7 +360,7 @@ process_helper_msgs (void *cls,
        GNUNET_break (0);
        break;
       }
        GNUNET_break (0);
        break;
       }
-      ds->progress_callback (ds->progress_callback_cls, 
+      ds->progress_callback (ds->progress_callback_cls,
                             filename, GNUNET_YES,
                             GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED);
       if (0 < left)
                             filename, GNUNET_YES,
                             GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED);
       if (0 < left)
@@ -326,17 +372,19 @@ process_helper_msgs (void *cls,
          break;
        }
        /* having full filenames is too dangerous; always make sure we clean them up */
          break;
        }
        /* having full filenames is too dangerous; always make sure we clean them up */
-       GNUNET_CONTAINER_meta_data_delete (ds->pos->meta, 
+       GNUNET_CONTAINER_meta_data_delete (ds->pos->meta,
                                           EXTRACTOR_METATYPE_FILENAME,
                                           NULL, 0);
                                           EXTRACTOR_METATYPE_FILENAME,
                                           NULL, 0);
+       /* instead, put in our 'safer' original filename */
        GNUNET_CONTAINER_meta_data_insert (ds->pos->meta, "<libgnunetfs>",
        GNUNET_CONTAINER_meta_data_insert (ds->pos->meta, "<libgnunetfs>",
-                                          EXTRACTOR_METATYPE_FILENAME,
+                                          EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
                                           EXTRACTOR_METAFORMAT_UTF8, "text/plain",
                                           EXTRACTOR_METAFORMAT_UTF8, "text/plain",
-                                          ds->pos->short_filename, 
+                                          ds->pos->short_filename,
                                           strlen (ds->pos->short_filename) + 1);
       }
                                           strlen (ds->pos->short_filename) + 1);
       }
-      ds->pos = advance (ds->pos);      
-      return;
+      ds->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (ds->pos->meta);
+      ds->pos = advance (ds->pos);
+      return GNUNET_OK;
     }
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED:
     if (NULL != ds->pos)
     }
   case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED:
     if (NULL != ds->pos)
@@ -348,26 +396,42 @@ process_helper_msgs (void *cls,
     {
       GNUNET_break (0);
       break;
     {
       GNUNET_break (0);
       break;
-    }   
+    }
     if (NULL == ds->toplevel)
     {
       GNUNET_break (0);
       break;
     }
     if (NULL == ds->toplevel)
     {
       GNUNET_break (0);
       break;
     }
-    GNUNET_HELPER_stop (ds->helper);
-    ds->helper = NULL;
-    ds->progress_callback (ds->progress_callback_cls, 
-                          NULL, GNUNET_SYSERR,
-                          GNUNET_FS_DIRSCANNER_FINISHED);    
-    return;
+    ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan,
+                                             ds);
+    return GNUNET_OK;
   default:
     GNUNET_break (0);
     break;
   }
   default:
     GNUNET_break (0);
     break;
   }
-  ds->progress_callback (ds->progress_callback_cls, 
+  ds->progress_callback (ds->progress_callback_cls,
                         NULL, GNUNET_SYSERR,
                         GNUNET_FS_DIRSCANNER_INTERNAL_ERROR);
                         NULL, GNUNET_SYSERR,
                         GNUNET_FS_DIRSCANNER_INTERNAL_ERROR);
+  return GNUNET_OK;
+}
+
 
 
+/**
+ * Function called if our helper process died.
+ *
+ * @param cls the 'struct GNUNET_FS_DirScanner' callback.
+ */
+static void
+helper_died_cb (void *cls)
+{
+  struct GNUNET_FS_DirScanner *ds = cls;
+
+  ds->helper = NULL;
+  if (NULL != ds->stop_task)
+    return; /* normal death, was finished */
+  ds->progress_callback (ds->progress_callback_cls,
+                        NULL, GNUNET_SYSERR,
+                        GNUNET_FS_DIRSCANNER_INTERNAL_ERROR);
 }
 
 
 }
 
 
@@ -375,7 +439,7 @@ process_helper_msgs (void *cls,
  * Start a directory scanner thread.
  *
  * @param filename name of the directory to scan
  * Start a directory scanner thread.
  *
  * @param filename name of the directory to scan
- * @param GNUNET_YES to not to run libextractor on files (only build a tree)
+ * @param disable_extractor #GNUNET_YES to not to run libextractor on files (only build a tree)
  * @param ex if not NULL, must be a list of extra plugins for extractor
  * @param cb the callback to call when there are scanning progress messages
  * @param cb_cls closure for 'cb'
  * @param ex if not NULL, must be a list of extra plugins for extractor
  * @param cb the callback to call when there are scanning progress messages
  * @param cb_cls closure for 'cb'
@@ -384,7 +448,7 @@ process_helper_msgs (void *cls,
 struct GNUNET_FS_DirScanner *
 GNUNET_FS_directory_scan_start (const char *filename,
                                int disable_extractor, const char *ex,
 struct GNUNET_FS_DirScanner *
 GNUNET_FS_directory_scan_start (const char *filename,
                                int disable_extractor, const char *ex,
-                               GNUNET_FS_DirScannerProgressCallback cb, 
+                               GNUNET_FS_DirScannerProgressCallback cb,
                                void *cb_cls)
 {
   struct stat sbuf;
                                void *cb_cls)
 {
   struct stat sbuf;
@@ -399,24 +463,25 @@ GNUNET_FS_directory_scan_start (const char *filename,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Starting to scan directory `%s'\n",
              filename_expanded);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Starting to scan directory `%s'\n",
              filename_expanded);
-  ds = GNUNET_malloc (sizeof (struct GNUNET_FS_DirScanner));
+  ds = GNUNET_new (struct GNUNET_FS_DirScanner);
   ds->progress_callback = cb;
   ds->progress_callback_cls = cb_cls;
   ds->filename_expanded = filename_expanded;
   ds->progress_callback = cb;
   ds->progress_callback_cls = cb_cls;
   ds->filename_expanded = filename_expanded;
-  if (disable_extractor)  
+  if (disable_extractor)
     ds->ex_arg = GNUNET_strdup ("-");
     ds->ex_arg = GNUNET_strdup ("-");
-  else 
+  else
     ds->ex_arg = (NULL != ex) ? GNUNET_strdup (ex) : NULL;
   ds->args[0] = "gnunet-helper-fs-publish";
   ds->args[1] = ds->filename_expanded;
   ds->args[2] = ds->ex_arg;
   ds->args[3] = NULL;
     ds->ex_arg = (NULL != ex) ? GNUNET_strdup (ex) : NULL;
   ds->args[0] = "gnunet-helper-fs-publish";
   ds->args[1] = ds->filename_expanded;
   ds->args[2] = ds->ex_arg;
   ds->args[3] = NULL;
-  ds->helper = GNUNET_HELPER_start ("gnunet-helper-fs-publish",
+  ds->helper = GNUNET_HELPER_start (GNUNET_NO,
+                                   "gnunet-helper-fs-publish",
                                    ds->args,
                                    &process_helper_msgs,
                                    ds->args,
                                    &process_helper_msgs,
-                                   ds);
+                                   &helper_died_cb, ds);
   if (NULL == ds->helper)
   if (NULL == ds->helper)
-  {
+    {
     GNUNET_free (filename_expanded);
     GNUNET_free (ds);
     return NULL;
     GNUNET_free (filename_expanded);
     GNUNET_free (ds);
     return NULL;