adding single location for no_forcestart configuration list
[oweals/gnunet.git] / src / fs / gnunet-helper-fs-publish.c
index d429f603db1efa7648a71625d84b5f09fde93c3a..c64dece4224a152d1c51c692232362dddcf19d0a 100644 (file)
@@ -75,7 +75,7 @@ struct ScanTreeNode
   uint64_t file_size;
 
   /**
-   * GNUNET_YES if this is a directory
+   * #GNUNET_YES if this is a directory
    */
   int is_directory;
 
@@ -87,6 +87,11 @@ struct ScanTreeNode
  */
 static struct EXTRACTOR_PluginList *plugins;
 
+/**
+ * File descriptor we use for IPC with the parent.
+ */
+static int output_stream;
+
 
 /**
  * Add meta data that libextractor finds to our meta data
@@ -102,7 +107,7 @@ static struct EXTRACTOR_PluginList *plugins;
  * @param data_mime_type mime-type of data (not of the original file);
  *        can be NULL (if mime-type is not known)
  * @param data actual meta-data found
- * @param data_len number of bytes in data
+ * @param data_len number of bytes in @a data
  * @return always 0 to continue extracting
  */
 static int
@@ -112,18 +117,31 @@ add_to_md (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type,
 {
   struct GNUNET_CONTAINER_MetaData *md = cls;
 
-  (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
-                                            data_mime_type, data, data_len);
+  if ( ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
+       (EXTRACTOR_METAFORMAT_C_STRING == format)) &&
+       ('\0' != data[data_len - 1]) )
+  {
+    char zdata[data_len + 1];
+    memcpy (zdata, data, data_len);
+    zdata[data_len] = '\0';
+    (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
+                                             data_mime_type, zdata, data_len + 1);
+  }
+  else
+  {
+    (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
+                                             data_mime_type, data, data_len);
+  }
   return 0;
 }
 
 
 /**
- * Free memory of the 'tree' structure
+ * Free memory of the @a tree structure
  *
  * @param tree tree to free
  */
-static void 
+static void
 free_tree (struct ScanTreeNode *tree)
 {
   struct ScanTreeNode *pos;
@@ -133,18 +151,18 @@ free_tree (struct ScanTreeNode *tree)
   if (NULL != tree->parent)
     GNUNET_CONTAINER_DLL_remove (tree->parent->children_head,
                                 tree->parent->children_tail,
-                                tree);                          
+                                tree);                         
   GNUNET_free (tree->filename);
   GNUNET_free (tree);
 }
 
 
 /**
- * Write 'size' bytes from 'buf' into 'out'.
+ * Write @a size bytes from @a buf into the #output_stream.
  *
  * @param buf buffer with data to write
  * @param size number of bytes to write
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 write_all (const void *buf,
@@ -157,7 +175,7 @@ write_all (const void *buf,
   total = 0;
   do
   {
-    wr = write (1,
+    wr = write (output_stream,
                &cbuf[total],
                size - total);
     if (wr > 0)
@@ -176,8 +194,8 @@ write_all (const void *buf,
  *
  * @param message_type message type to use
  * @param data data to append, NULL for none
- * @param data_length number of bytes in data
- * @return GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
+ * @param data_length number of bytes in @a data
+ * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
  */
 static int
 write_message (uint16_t message_type,
@@ -187,7 +205,8 @@ write_message (uint16_t message_type,
   struct GNUNET_MessageHeader hdr;
 
 #if 0
-  fprintf (stderr, "Helper sends %u-byte message of type %u\n",
+  fprintf (stderr,
+          "Helper sends %u-byte message of type %u\n",
           (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length),
           (unsigned int) message_type);
 #endif
@@ -211,8 +230,8 @@ write_message (uint16_t message_type,
  *
  * @param filename file or directory to scan
  * @param dst where to store the resulting share tree item;
- *         NULL is stored in 'dst' upon recoverable errors (GNUNET_OK is returned)
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ *         NULL is stored in @a dst upon recoverable errors (#GNUNET_OK is returned)
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 preprocess_file (const char *filename,
@@ -241,9 +260,9 @@ struct RecursionContext
  * of the files in the directory to the tree.  Called by the directory
  * scanner to initiate the scan.  Does NOT yet add any metadata.
  *
- * @param cls the 'struct RecursionContext'
+ * @param cls the `struct RecursionContext`
  * @param filename file or directory to scan
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 scan_callback (void *cls,
@@ -276,8 +295,8 @@ scan_callback (void *cls,
  *
  * @param filename file or directory to scan
  * @param dst where to store the resulting share tree item;
- *         NULL is stored in 'dst' upon recoverable errors (GNUNET_OK is returned) 
- * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ *         NULL is stored in @a dst upon recoverable errors (#GNUNET_OK is returned)
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 preprocess_file (const char *filename,
@@ -304,12 +323,12 @@ preprocess_file (const char *filename,
 
   /* Report the progress */
   if (GNUNET_OK !=
-      write_message (S_ISDIR (sbuf.st_mode) 
+      write_message (S_ISDIR (sbuf.st_mode)
                     ? GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY
                     : GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE,
                     filename, strlen (filename) + 1))
     return GNUNET_SYSERR;
-  item = GNUNET_malloc (sizeof (struct ScanTreeNode));
+  item = GNUNET_new (struct ScanTreeNode);
   item->filename = GNUNET_strdup (filename);
   item->is_directory = (S_ISDIR (sbuf.st_mode)) ? GNUNET_YES : GNUNET_NO;
   item->file_size = fsize;
@@ -319,9 +338,9 @@ preprocess_file (const char *filename,
 
     rc.parent = item;
     rc.stop = GNUNET_NO;
-    GNUNET_DISK_directory_scan (filename, 
-                               &scan_callback, 
-                               &rc);    
+    GNUNET_DISK_directory_scan (filename,
+                               &scan_callback,
+                               &rc);
     if ( (GNUNET_YES == rc.stop) ||
         (GNUNET_OK !=
          write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY,
@@ -340,11 +359,11 @@ preprocess_file (const char *filename,
  * Extract metadata from files.
  *
  * @param item entry we are processing
- * @return GNUNET_OK on success, GNUNET_SYSERR on fatal errors
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on fatal errors
  */
 static int
 extract_files (struct ScanTreeNode *item)
-{  
+{
   struct GNUNET_CONTAINER_MetaData *meta;
   ssize_t size;
   size_t slen;
@@ -361,7 +380,7 @@ extract_files (struct ScanTreeNode *item)
        return GNUNET_SYSERR;
     return GNUNET_OK;
   }
-  
+
   /* this is the expensive operation, *afterwards* we'll check for aborts */
   meta = GNUNET_CONTAINER_meta_data_create ();
   EXTRACTOR_extract (plugins, item->filename, NULL, 0, &add_to_md, meta);
@@ -374,13 +393,18 @@ extract_files (struct ScanTreeNode *item)
     if (GNUNET_OK !=
        write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA,
                       item->filename, slen))
-      return GNUNET_SYSERR;    
+      return GNUNET_SYSERR;
     return GNUNET_OK;
   }
+  else if (size > (UINT16_MAX - sizeof (struct GNUNET_MessageHeader) - slen))
+  {
+    /* We can't transfer more than 64k bytes in one message. */
+    size = UINT16_MAX - sizeof (struct GNUNET_MessageHeader) - slen;
+  }
   {
     char buf[size + slen];
     char *dst = &buf[slen];
-    
+
     memcpy (buf, item->filename, slen);
     size = GNUNET_CONTAINER_meta_data_serialize (meta,
                                                 &dst, size,
@@ -393,7 +417,7 @@ extract_files (struct ScanTreeNode *item)
     GNUNET_CONTAINER_meta_data_destroy (meta);
     if (GNUNET_OK !=
        write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA,
-                      buf, 
+                      buf,
                       slen + size))
       return GNUNET_SYSERR;
   }
@@ -423,6 +447,29 @@ ignore_sigpipe ()
     fprintf (stderr,
              "Failed to install SIGPIPE handler: %s\n", strerror (errno));
 }
+
+
+/**
+ * Turn the given file descriptor in to '/dev/null'.
+ *
+ * @param fd fd to bind to /dev/null
+ * @param flags flags to use (O_RDONLY or O_WRONLY)
+ */
+static void
+make_dev_zero (int fd,
+              int flags)
+{
+  int z;
+
+  GNUNET_assert (0 == close (fd));
+  z = open ("/dev/null", flags);
+  GNUNET_assert (-1 != z);
+  if (z == fd)
+    return;
+  dup2 (z, fd);
+  GNUNET_assert (0 == close (z));
+}
+
 #endif
 
 
@@ -436,8 +483,9 @@ ignore_sigpipe ()
  *                 otherwise custom plugins to load from LE
  * @return 0 on success
  */
-int main(int argc,
-        char *const *argv)
+int
+main (int argc,
+      char *const *argv)
 {
   const char *filename_expanded;
   const char *ex;
@@ -451,17 +499,25 @@ int main(int argc,
   /* Get utf-8-encoded arguments */
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
     return 5;
+  output_stream = 1; /* stdout */
 #else
   ignore_sigpipe ();
+  /* move stdout to some other FD for IPC, bind
+     stdout/stderr to /dev/null */
+  output_stream = dup (1);
+  make_dev_zero (1, O_WRONLY);
+  make_dev_zero (2, O_WRONLY);
 #endif
 
   /* parse command line */
   if ( (3 != argc) && (2 != argc) )
   {
-    FPRINTF (stderr, 
+    FPRINTF (stderr,
             "%s",
             "gnunet-helper-fs-publish needs exactly one or two arguments\n");
+#if WINDOWS
     GNUNET_free ((void*) argv);
+#endif
     return 1;
   }
   filename_expanded = argv[1];
@@ -476,22 +532,26 @@ int main(int argc,
   }
 
   /* scan tree to find out how much work there is to be done */
-  if (GNUNET_OK != preprocess_file (filename_expanded, 
+  if (GNUNET_OK != preprocess_file (filename_expanded,
                                    &root))
   {
     (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0);
     EXTRACTOR_plugin_remove_all (plugins);
+#if WINDOWS
     GNUNET_free ((void*) argv);
+#endif
     return 2;
   }
-  /* signal that we're done counting files, so that a percentage of 
+  /* signal that we're done counting files, so that a percentage of
      progress can now be calculated */
   if (GNUNET_OK !=
       write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE, NULL, 0))
   {
     EXTRACTOR_plugin_remove_all (plugins);
+#if WINDOWS
     GNUNET_free ((void*) argv);
-    return 3;  
+#endif
+    return 3;
   }
   if (NULL != root)
   {
@@ -501,7 +561,9 @@ int main(int argc,
       (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0);
       free_tree (root);
       EXTRACTOR_plugin_remove_all (plugins);
+#if WINDOWS
       GNUNET_free ((void*) argv);
+#endif
       return 4;
     }
     free_tree (root);
@@ -509,7 +571,9 @@ int main(int argc,
   /* enable "clean" shutdown by telling parent that we are done */
   (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED, NULL, 0);
   EXTRACTOR_plugin_remove_all (plugins);
-  GNUNET_free ((void*) argv);  
+#if WINDOWS
+  GNUNET_free ((void*) argv);
+#endif
   return 0;
 }