Esempio n. 1
0
/**
 * Print an entry in a directory.
 *
 * @param cls closure (not used)
 * @param filename name of the file in the directory
 * @param uri URI of the file
 * @param meta metadata for the file; metadata for
 *        the directory if everything else is NULL/zero
 * @param length length of the available data for the file
 *           (of type size_t since data must certainly fit
 *            into memory; if files are larger than size_t
 *            permits, then they will certainly not be
 *            embedded with the directory itself).
 * @param data data available for the file (length bytes)
 */
static void
print_entry (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri,
             const struct GNUNET_CONTAINER_MetaData *meta, size_t length,
             const void *data)
{
  char *string;
  char *name;

  name =
      GNUNET_CONTAINER_meta_data_get_by_type (meta,
                                              EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
  if (uri == NULL)
  {
    printf (_("Directory `%s' meta data:\n"), name);
    GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL);
    printf ("\n");
    printf (_("Directory `%s' contents:\n"), name);
    GNUNET_free (name);
    return;
  }
  string = GNUNET_FS_uri_to_string (uri);
  printf ("%s (%s):\n", name, string);
  GNUNET_free (string);
  GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL);
  printf ("\n");
  GNUNET_free (name);
}
Esempio n. 2
0
/**
 * Iterate over all entries in a directory.  Note that directories
 * are structured such that it is possible to iterate over the
 * individual blocks as well as over the entire directory.  Thus
 * a client can call this function on the buffer in the
 * GNUNET_FS_ProgressCallback.  Also, directories can optionally
 * include the contents of (small) files embedded in the directory
 * itself; for those files, the processor may be given the
 * contents of the file directly by this function.
 * <p>
 *
 * Note that this function maybe called on parts of directories.  Thus
 * parser errors should not be reported _at all_ (with GNUNET_break).
 * Still, if some entries can be recovered despite these parsing
 * errors, the function should try to do this.
 *
 * @param size number of bytes in data
 * @param data pointer to the beginning of the directory
 * @param offset offset of data in the directory
 * @param dep function to call on each entry
 * @param dep_cls closure for dep
 * @return GNUNET_OK if this could be a block in a directory,
 *         GNUNET_NO if this could be part of a directory (but not 100% OK)
 *         GNUNET_SYSERR if 'data' does not represent a directory
 */
int
GNUNET_FS_directory_list_contents (size_t size, const void *data,
                                   uint64_t offset,
                                   GNUNET_FS_DirectoryEntryProcessor dep,
                                   void *dep_cls)
{
  struct GetFullDataClosure full_data;
  const char *cdata = data;
  char *emsg;
  uint64_t pos;
  uint64_t align;
  uint32_t mdSize;
  uint64_t epos;
  struct GNUNET_FS_Uri *uri;
  struct GNUNET_CONTAINER_MetaData *md;
  char *filename;

  if ((offset == 0) &&
      ((size < 8 + sizeof (uint32_t)) ||
       (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8))))
    return GNUNET_SYSERR;
  pos = offset;
  if (offset == 0)
  {
    GNUNET_memcpy (&mdSize, &cdata[8], sizeof (uint32_t));
    mdSize = ntohl (mdSize);
    if (mdSize > size - 8 - sizeof (uint32_t))
    {
      /* invalid size */
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _("MAGIC mismatch.  This is not a GNUnet directory.\n"));
      return GNUNET_SYSERR;
    }
    md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 + sizeof (uint32_t)],
                                                 mdSize);
    if (md == NULL)
    {
      GNUNET_break (0);
      return GNUNET_SYSERR;     /* malformed ! */
    }
    dep (dep_cls, NULL, NULL, md, 0, NULL);
    GNUNET_CONTAINER_meta_data_destroy (md);
    pos = 8 + sizeof (uint32_t) + mdSize;
  }
  while (pos < size)
  {
    /* find end of URI */
    if (cdata[pos] == '\0')
    {
      /* URI is never empty, must be end of block,
       * skip to next alignment */
      align = ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE;
      if (align == pos)
      {
        /* if we were already aligned, still skip a block! */
        align += DBLOCK_SIZE;
      }
      pos = align;
      if (pos >= size)
      {
        /* malformed - or partial download... */
        break;
      }
    }
    epos = pos;
    while ((epos < size) && (cdata[epos] != '\0'))
      epos++;
    if (epos >= size)
      return GNUNET_NO;         /* malformed - or partial download */

    uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg);
    pos = epos + 1;
    if (uri == NULL)
    {
      GNUNET_free (emsg);
      pos--;                    /* go back to '\0' to force going to next alignment */
      continue;
    }
    if (GNUNET_FS_uri_test_ksk (uri))
    {
      GNUNET_FS_uri_destroy (uri);
      GNUNET_break (0);
      return GNUNET_NO;         /* illegal in directory! */
    }

    GNUNET_memcpy (&mdSize, &cdata[pos], sizeof (uint32_t));
    mdSize = ntohl (mdSize);
    pos += sizeof (uint32_t);
    if (pos + mdSize > size)
    {
      GNUNET_FS_uri_destroy (uri);
      return GNUNET_NO;         /* malformed - or partial download */
    }

    md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize);
    if (md == NULL)
    {
      GNUNET_FS_uri_destroy (uri);
      GNUNET_break (0);
      return GNUNET_NO;         /* malformed ! */
    }
    pos += mdSize;
    filename =
        GNUNET_CONTAINER_meta_data_get_by_type (md,
                                                EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
    full_data.size = 0;
    full_data.data = NULL;
    GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data);
    if (dep != NULL)
    {
      dep (dep_cls, filename, uri, md, full_data.size, full_data.data);
    }
    GNUNET_free_non_null (full_data.data);
    GNUNET_free_non_null (filename);
    GNUNET_CONTAINER_meta_data_destroy (md);
    GNUNET_FS_uri_destroy (uri);
  }
  return GNUNET_OK;
}
Esempio n. 3
0
/**
 * Process a share item tree, moving frequent keywords up and
 * copying frequent metadata up.
 *
 * @param tc trim context with hash maps to use
 * @param tree tree to trim
 */
static void
share_tree_trim (struct TrimContext *tc,
		 struct GNUNET_FS_ShareTreeItem *tree)
{
  struct GNUNET_FS_ShareTreeItem *pos;
  unsigned int num_children;

  /* first, trim all children */
  num_children = 0;
  for (pos = tree->children_head; NULL != pos; pos = pos->next)
  {
    share_tree_trim (tc, pos);
    num_children++;
  }

  /* consider adding filename to directory meta data */
  if (tree->is_directory == GNUNET_YES)
  {
    const char *user = getenv ("USER");
    if ( (user == NULL) || 
	 (0 != strncasecmp (user, tree->short_filename, strlen(user))))
    {
      /* only use filename if it doesn't match $USER */
      if (NULL == tree->meta)
	tree->meta = GNUNET_CONTAINER_meta_data_create ();
      GNUNET_CONTAINER_meta_data_insert (tree->meta, "<libgnunetfs>",
					 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
					 EXTRACTOR_METAFORMAT_UTF8,
					 "text/plain", tree->short_filename,
					 strlen (tree->short_filename) + 1);
    }
  }

  if (1 >= num_children)
    return; /* nothing to trim */
  
  /* now, count keywords and meta data in children */
  for (pos = tree->children_head; NULL != pos; pos = pos->next)
  {
    if (NULL != pos->meta)
      GNUNET_CONTAINER_meta_data_iterate (pos->meta, &add_to_meta_counter, tc->metacounter);    
    if (NULL != pos->ksk_uri)
      GNUNET_FS_uri_ksk_get_keywords (pos->ksk_uri, &add_to_keyword_counter, tc->keywordcounter);
  }

  /* calculate threshold for moving keywords / meta data */
  tc->move_threshold = 1 + (num_children / 2);

  /* remove high-frequency keywords from children */
  for (pos = tree->children_head; NULL != pos; pos = pos->next)
  {
    tc->pos = pos;
    if (NULL != pos->ksk_uri)
    {
      struct GNUNET_FS_Uri *ksk_uri_copy = GNUNET_FS_uri_dup (pos->ksk_uri);
      GNUNET_FS_uri_ksk_get_keywords (ksk_uri_copy, &remove_high_frequency_keywords, tc);
      GNUNET_FS_uri_destroy (ksk_uri_copy);
    }
  }

  /* add high-frequency meta data and keywords to parent */
  tc->pos = tree;
  GNUNET_CONTAINER_multihashmap_iterate (tc->keywordcounter, 
					 &migrate_and_drop_keywords,
					 tc);
  GNUNET_CONTAINER_multihashmap_iterate (tc->metacounter, 
					 &migrate_and_drop_metadata,
					 tc);
}
/**
 * Extend metadata.  Merges the meta data from the second argument
 * into the first, discarding duplicate key-value pairs.
 *
 * @param md metadata to extend
 * @param in metadata to merge
 */
void
GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md,
                                  const struct GNUNET_CONTAINER_MetaData *in)
{
  GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md);
}
Esempio n. 5
0
/**
 * Called by FS client to give information about the progress of an
 * operation.
 *
 * @param cls closure
 * @param info details about the event, specifying the event type
 *        and various bits about the event
 * @return client-context (for the next progress call
 *         for this operation; should be set to NULL for
 *         SUSPEND and STOPPED events).  The value returned
 *         will be passed to future callbacks in the respective
 *         field in the GNUNET_FS_ProgressInfo struct.
 */
static void *
progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
{
  static unsigned int cnt;
  int is_directory;
  char *uri;
  char *filename;

  switch (info->status)
  {
  case GNUNET_FS_STATUS_SEARCH_START:
    break;
  case GNUNET_FS_STATUS_SEARCH_RESULT:
    if (db != NULL)
      GNUNET_FS_directory_builder_add (db,
                                       info->value.search.specifics.result.uri,
                                       info->value.search.specifics.result.meta,
                                       NULL);
    uri = GNUNET_FS_uri_to_string (info->value.search.specifics.result.uri);
    printf ("#%u:\n", cnt++);
    filename =
        GNUNET_CONTAINER_meta_data_get_by_type (info->value.search.
                                                specifics.result.meta,
                                                EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
    is_directory =
        GNUNET_FS_meta_data_test_for_directory (info->value.search.
                                                specifics.result.meta);
    if (filename != NULL)
    {
      GNUNET_DISK_filename_canonicalize (filename);
      if (GNUNET_YES == is_directory)
        printf ("gnunet-download -o \"%s%s\" -R %s\n", filename, GNUNET_FS_DIRECTORY_EXT, uri);
      else
        printf ("gnunet-download -o \"%s\" %s\n", filename, uri);
    }
    else if (GNUNET_YES == is_directory)
      printf ("gnunet-download -o \"collection%s\" -R %s\n", GNUNET_FS_DIRECTORY_EXT, uri);
    else
      printf ("gnunet-download %s\n", uri);
    if (verbose)
      GNUNET_CONTAINER_meta_data_iterate (info->value.search.specifics.
                                          result.meta, &item_printer, NULL);
    printf ("\n");
    fflush (stdout);
    GNUNET_free_non_null (filename);
    GNUNET_free (uri);
    results++;
    if ((results_limit > 0) && (results >= results_limit))
      GNUNET_SCHEDULER_shutdown ();
    break;
  case GNUNET_FS_STATUS_SEARCH_UPDATE:
    break;
  case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
    /* ignore */
    break;
  case GNUNET_FS_STATUS_SEARCH_ERROR:
    FPRINTF (stderr, _("Error searching: %s.\n"),
             info->value.search.specifics.error.message);
    GNUNET_SCHEDULER_shutdown ();
    break;
  case GNUNET_FS_STATUS_SEARCH_STOPPED:
    GNUNET_SCHEDULER_add_now (&clean_task, NULL);
    break;
  default:
    FPRINTF (stderr, _("Unexpected status: %d\n"), info->status);
    break;
  }
  return NULL;
}