+/**
+ * Add an entry to a directory.
+ *
+ * @param bld directory to extend
+ * @param uri uri of the entry (must not be a KSK)
+ * @param md metadata of the entry
+ * @param data raw data of the entry, can be NULL, otherwise
+ * data must point to exactly the number of bytes specified
+ * by the uri which must be of type LOC or CHK
+ */
+void
+GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld,
+ const struct GNUNET_FS_Uri *uri,
+ const struct GNUNET_CONTAINER_MetaData *md,
+ const void *data)
+{
+ struct GNUNET_FS_Uri *curi;
+ struct BuilderEntry *e;
+ uint64_t fsize;
+ uint32_t big;
+ ssize_t ret;
+ size_t mds;
+ size_t mdxs;
+ char *uris;
+ char *ser;
+ char *sptr;
+ size_t slen;
+ struct GNUNET_CONTAINER_MetaData *meta;
+ const struct GNUNET_CONTAINER_MetaData *meta_use;
+
+ GNUNET_assert (!GNUNET_FS_uri_test_ksk (uri));
+ if (NULL != data)
+ {
+ GNUNET_assert (!GNUNET_FS_uri_test_sks (uri));
+ if (GNUNET_FS_uri_test_chk (uri))
+ {
+ fsize = GNUNET_FS_uri_chk_get_file_size (uri);
+ }
+ else
+ {
+ curi = GNUNET_FS_uri_loc_get_uri (uri);
+ GNUNET_assert (NULL != curi);
+ fsize = GNUNET_FS_uri_chk_get_file_size (curi);
+ GNUNET_FS_uri_destroy (curi);
+ }
+ }
+ else
+ {
+ fsize = 0; /* not given */
+ }
+ if (fsize > MAX_INLINE_SIZE)
+ fsize = 0; /* too large */
+ uris = GNUNET_FS_uri_to_string (uri);
+ slen = strlen (uris) + 1;
+ mds = GNUNET_CONTAINER_meta_data_get_serialized_size (md);
+ meta_use = md;
+ meta = NULL;
+ if (fsize > 0)
+ {
+ meta = GNUNET_CONTAINER_meta_data_duplicate (md);
+ GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>",
+ EXTRACTOR_METATYPE_GNUNET_FULL_DATA,
+ EXTRACTOR_METAFORMAT_BINARY, NULL, data,
+ fsize);
+ mdxs = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
+ if ((slen + sizeof (uint32_t) + mdxs - 1) / DBLOCK_SIZE ==
+ (slen + sizeof (uint32_t) + mds - 1) / DBLOCK_SIZE)
+ {
+ /* adding full data would not cause us to cross
+ * additional blocks, so add it! */
+ meta_use = meta;
+ mds = mdxs;
+ }
+ }
+
+ if (mds > GNUNET_MAX_MALLOC_CHECKED / 2)
+ mds = GNUNET_MAX_MALLOC_CHECKED / 2;
+ e = GNUNET_malloc (sizeof (struct BuilderEntry) + slen + mds +
+ sizeof (uint32_t));
+ ser = (char *) &e[1];
+ memcpy (ser, uris, slen);
+ GNUNET_free (uris);
+ sptr = &ser[slen + sizeof (uint32_t)];
+ ret =
+ GNUNET_CONTAINER_meta_data_serialize (meta_use, &sptr, mds,
+ GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
+ if (NULL != meta)
+ GNUNET_CONTAINER_meta_data_destroy (meta);
+ if (ret == -1)
+ mds = 0;
+ else
+ mds = ret;
+ big = htonl (mds);
+ memcpy (&ser[slen], &big, sizeof (uint32_t));
+ e->len = slen + sizeof (uint32_t) + mds;
+ e->next = bld->head;
+ bld->head = e;
+ bld->count++;
+}