aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_directory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/fs_directory.c')
-rw-r--r--src/fs/fs_directory.c551
1 files changed, 259 insertions, 292 deletions
diff --git a/src/fs/fs_directory.c b/src/fs/fs_directory.c
index dbd10c35e..f22480d5f 100644
--- a/src/fs/fs_directory.c
+++ b/src/fs/fs_directory.c
@@ -50,20 +50,22 @@
50 * @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if 50 * @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if
51 * we have no mime-type information (treat as 'GNUNET_NO') 51 * we have no mime-type information (treat as 'GNUNET_NO')
52 */ 52 */
53int 53int
54GNUNET_FS_meta_data_test_for_directory (const struct GNUNET_CONTAINER_MetaData *md) 54GNUNET_FS_meta_data_test_for_directory (const struct GNUNET_CONTAINER_MetaData
55 *md)
55{ 56{
56 char *mime; 57 char *mime;
57 int ret; 58 int ret;
58 59
59 if (NULL == md) 60 if (NULL == md)
60 return GNUNET_SYSERR; 61 return GNUNET_SYSERR;
61 mime = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); 62 mime =
63 GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE);
62 if (mime == NULL) 64 if (mime == NULL)
63 return GNUNET_SYSERR; 65 return GNUNET_SYSERR;
64 ret = (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)) ? GNUNET_YES : GNUNET_NO; 66 ret = (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)) ? GNUNET_YES : GNUNET_NO;
65 GNUNET_free (mime); 67 GNUNET_free (mime);
66 return ret; 68 return ret;
67} 69}
68 70
69 71
@@ -77,29 +79,29 @@ void
77GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md) 79GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md)
78{ 80{
79 char *mime; 81 char *mime;
80 82
81 mime = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); 83 mime =
84 GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE);
82 if (mime != NULL) 85 if (mime != NULL)
83 { 86 {
84 GNUNET_break (0 == strcmp (mime, 87 GNUNET_break (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME));
85 GNUNET_FS_DIRECTORY_MIME)); 88 GNUNET_free (mime);
86 GNUNET_free (mime); 89 return;
87 return; 90 }
88 } 91 GNUNET_CONTAINER_meta_data_insert (md,
89 GNUNET_CONTAINER_meta_data_insert (md, 92 "<gnunet>",
90 "<gnunet>", 93 EXTRACTOR_METATYPE_MIMETYPE,
91 EXTRACTOR_METATYPE_MIMETYPE, 94 EXTRACTOR_METAFORMAT_UTF8,
92 EXTRACTOR_METAFORMAT_UTF8, 95 "text/plain",
93 "text/plain", 96 GNUNET_FS_DIRECTORY_MIME,
94 GNUNET_FS_DIRECTORY_MIME, 97 strlen (GNUNET_FS_DIRECTORY_MIME) + 1);
95 strlen (GNUNET_FS_DIRECTORY_MIME)+1);
96} 98}
97 99
98 100
99/** 101/**
100 * Closure for 'find_full_data'. 102 * Closure for 'find_full_data'.
101 */ 103 */
102struct GetFullDataClosure 104struct GetFullDataClosure
103{ 105{
104 106
105 /** 107 /**
@@ -130,30 +132,26 @@ struct GetFullDataClosure
130 * @param data actual meta-data found 132 * @param data actual meta-data found
131 * @param data_len number of bytes in data 133 * @param data_len number of bytes in data
132 * @return 0 to continue extracting, 1 to abort 134 * @return 0 to continue extracting, 1 to abort
133 */ 135 */
134static int 136static int
135find_full_data (void *cls, 137find_full_data (void *cls,
136 const char *plugin_name, 138 const char *plugin_name,
137 enum EXTRACTOR_MetaType type, 139 enum EXTRACTOR_MetaType type,
138 enum EXTRACTOR_MetaFormat format, 140 enum EXTRACTOR_MetaFormat format,
139 const char *data_mime_type, 141 const char *data_mime_type, const char *data, size_t data_len)
140 const char *data,
141 size_t data_len)
142{ 142{
143 struct GetFullDataClosure *gfdc = cls; 143 struct GetFullDataClosure *gfdc = cls;
144 144
145 if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) 145 if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA)
146 {
147 gfdc->size = data_len;
148 if (data_len > 0)
146 { 149 {
147 gfdc->size = data_len; 150 gfdc->data = GNUNET_malloc (data_len);
148 if (data_len > 0) 151 memcpy (gfdc->data, data, data_len);
149 {
150 gfdc->data = GNUNET_malloc (data_len);
151 memcpy (gfdc->data,
152 data,
153 data_len);
154 }
155 return 1;
156 } 152 }
153 return 1;
154 }
157 return 0; 155 return 0;
158} 156}
159 157
@@ -183,12 +181,12 @@ find_full_data (void *cls,
183 * GNUNET_NO if this could be part of a directory (but not 100% OK) 181 * GNUNET_NO if this could be part of a directory (but not 100% OK)
184 * GNUNET_SYSERR if 'data' does not represent a directory 182 * GNUNET_SYSERR if 'data' does not represent a directory
185 */ 183 */
186int 184int
187GNUNET_FS_directory_list_contents (size_t size, 185GNUNET_FS_directory_list_contents (size_t size,
188 const void *data, 186 const void *data,
189 uint64_t offset, 187 uint64_t offset,
190 GNUNET_FS_DirectoryEntryProcessor dep, 188 GNUNET_FS_DirectoryEntryProcessor dep,
191 void *dep_cls) 189 void *dep_cls)
192{ 190{
193 struct GetFullDataClosure full_data; 191 struct GetFullDataClosure full_data;
194 const char *cdata = data; 192 const char *cdata = data;
@@ -201,123 +199,110 @@ GNUNET_FS_directory_list_contents (size_t size,
201 struct GNUNET_CONTAINER_MetaData *md; 199 struct GNUNET_CONTAINER_MetaData *md;
202 char *filename; 200 char *filename;
203 201
204 if ( (offset == 0) && 202 if ((offset == 0) &&
205 ( (size < 8 + sizeof (uint32_t)) || 203 ((size < 8 + sizeof (uint32_t)) ||
206 (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8)) ) ) 204 (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8))))
205 {
206 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
207 _("MAGIC mismatch. This is not a GNUnet directory.\n"));
208 return GNUNET_SYSERR;
209 }
210 pos = offset;
211 if (offset == 0)
212 {
213 memcpy (&mdSize, &cdata[8], sizeof (uint32_t));
214 mdSize = ntohl (mdSize);
215 if (mdSize > size - 8 - sizeof (uint32_t))
207 { 216 {
217 /* invalid size */
208 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 218 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
209 _("MAGIC mismatch. This is not a GNUnet directory.\n")); 219 _("MAGIC mismatch. This is not a GNUnet directory.\n"));
210 return GNUNET_SYSERR; 220 return GNUNET_SYSERR;
211 } 221 }
212 pos = offset; 222 md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 +
213 if (offset == 0) 223 sizeof (uint32_t)],
224 mdSize);
225 if (md == NULL)
214 { 226 {
215 memcpy (&mdSize, &cdata[8], sizeof (uint32_t)); 227 GNUNET_break (0);
216 mdSize = ntohl (mdSize); 228 return GNUNET_SYSERR; /* malformed ! */
217 if (mdSize > size - 8 - sizeof (uint32_t))
218 {
219 /* invalid size */
220 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
221 _("MAGIC mismatch. This is not a GNUnet directory.\n"));
222 return GNUNET_SYSERR;
223 }
224 md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 +
225 sizeof (uint32_t)],
226 mdSize);
227 if (md == NULL)
228 {
229 GNUNET_break (0);
230 return GNUNET_SYSERR; /* malformed ! */
231 }
232 dep (dep_cls,
233 NULL,
234 NULL,
235 md,
236 0,
237 NULL);
238 GNUNET_CONTAINER_meta_data_destroy (md);
239 pos = 8 + sizeof (uint32_t) + mdSize;
240 } 229 }
230 dep (dep_cls, NULL, NULL, md, 0, NULL);
231 GNUNET_CONTAINER_meta_data_destroy (md);
232 pos = 8 + sizeof (uint32_t) + mdSize;
233 }
241 while (pos < size) 234 while (pos < size)
235 {
236 /* find end of URI */
237 if (cdata[pos] == '\0')
242 { 238 {
243 /* find end of URI */ 239 /* URI is never empty, must be end of block,
244 if (cdata[pos] == '\0') 240 * skip to next alignment */
245 { 241 align = ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE;
246 /* URI is never empty, must be end of block, 242 if (align == pos)
247 skip to next alignment */ 243 {
248 align = 244 /* if we were already aligned, still skip a block! */
249 ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE; 245 align += DBLOCK_SIZE;
250 if (align == pos) 246 }
251 { 247 pos = align;
252 /* if we were already aligned, still skip a block! */ 248 if (pos >= size)
253 align += DBLOCK_SIZE; 249 {
254 } 250 /* malformed - or partial download... */
255 pos = align; 251 break;
256 if (pos >= size) 252 }
257 { 253 }
258 /* malformed - or partial download... */ 254 epos = pos;
259 break; 255 while ((epos < size) && (cdata[epos] != '\0'))
260 } 256 epos++;
261 } 257 if (epos >= size)
262 epos = pos; 258 return GNUNET_NO; /* malformed - or partial download */
263 while ((epos < size) && (cdata[epos] != '\0')) 259
264 epos++; 260 uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg);
265 if (epos >= size) 261 pos = epos + 1;
266 return GNUNET_NO; /* malformed - or partial download */ 262 if (uri == NULL)
267 263 {
268 uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg); 264 GNUNET_free (emsg);
269 pos = epos + 1; 265 pos--; /* go back to '\0' to force going to next alignment */
270 if (uri == NULL) 266 continue;
271 { 267 }
272 GNUNET_free (emsg); 268 if (GNUNET_FS_uri_test_ksk (uri))
273 pos--; /* go back to '\0' to force going to next alignment */ 269 {
274 continue; 270 GNUNET_FS_uri_destroy (uri);
275 } 271 GNUNET_break (0);
276 if (GNUNET_FS_uri_test_ksk (uri)) 272 return GNUNET_NO; /* illegal in directory! */
277 { 273 }
278 GNUNET_FS_uri_destroy (uri);
279 GNUNET_break (0);
280 return GNUNET_NO; /* illegal in directory! */
281 }
282 274
283 memcpy (&mdSize, &cdata[pos], sizeof (uint32_t)); 275 memcpy (&mdSize, &cdata[pos], sizeof (uint32_t));
284 mdSize = ntohl (mdSize); 276 mdSize = ntohl (mdSize);
285 pos += sizeof (uint32_t); 277 pos += sizeof (uint32_t);
286 if (pos + mdSize > size) 278 if (pos + mdSize > size)
287 { 279 {
288 GNUNET_FS_uri_destroy (uri); 280 GNUNET_FS_uri_destroy (uri);
289 return GNUNET_NO; /* malformed - or partial download */ 281 return GNUNET_NO; /* malformed - or partial download */
290 } 282 }
291 283
292 md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize); 284 md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize);
293 if (md == NULL) 285 if (md == NULL)
294 { 286 {
295 GNUNET_FS_uri_destroy (uri);
296 GNUNET_break (0);
297 return GNUNET_NO; /* malformed ! */
298 }
299 pos += mdSize;
300 filename = GNUNET_CONTAINER_meta_data_get_by_type (md,
301 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
302 full_data.size = 0;
303 full_data.data = NULL;
304 GNUNET_CONTAINER_meta_data_iterate (md,
305 &find_full_data,
306 &full_data);
307 if (dep != NULL)
308 {
309 dep (dep_cls,
310 filename,
311 uri,
312 md,
313 full_data.size,
314 full_data.data);
315 }
316 GNUNET_free_non_null (full_data.data);
317 GNUNET_free_non_null (filename);
318 GNUNET_CONTAINER_meta_data_destroy (md);
319 GNUNET_FS_uri_destroy (uri); 287 GNUNET_FS_uri_destroy (uri);
288 GNUNET_break (0);
289 return GNUNET_NO; /* malformed ! */
320 } 290 }
291 pos += mdSize;
292 filename = GNUNET_CONTAINER_meta_data_get_by_type (md,
293 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
294 full_data.size = 0;
295 full_data.data = NULL;
296 GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data);
297 if (dep != NULL)
298 {
299 dep (dep_cls, filename, uri, md, full_data.size, full_data.data);
300 }
301 GNUNET_free_non_null (full_data.data);
302 GNUNET_free_non_null (filename);
303 GNUNET_CONTAINER_meta_data_destroy (md);
304 GNUNET_FS_uri_destroy (uri);
305 }
321 return GNUNET_OK; 306 return GNUNET_OK;
322} 307}
323 308
@@ -330,7 +315,7 @@ struct BuilderEntry
330 * This is a linked list. 315 * This is a linked list.
331 */ 316 */
332 struct BuilderEntry *next; 317 struct BuilderEntry *next;
333 318
334 /** 319 /**
335 * Length of this entry. 320 * Length of this entry.
336 */ 321 */
@@ -365,11 +350,12 @@ struct GNUNET_FS_DirectoryBuilder
365 * @param mdir metadata for the directory 350 * @param mdir metadata for the directory
366 */ 351 */
367struct GNUNET_FS_DirectoryBuilder * 352struct GNUNET_FS_DirectoryBuilder *
368GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData *mdir) 353GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData
354 *mdir)
369{ 355{
370 struct GNUNET_FS_DirectoryBuilder *ret; 356 struct GNUNET_FS_DirectoryBuilder *ret;
371 357
372 ret = GNUNET_malloc(sizeof(struct GNUNET_FS_DirectoryBuilder)); 358 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_DirectoryBuilder));
373 if (mdir != NULL) 359 if (mdir != NULL)
374 ret->meta = GNUNET_CONTAINER_meta_data_duplicate (mdir); 360 ret->meta = GNUNET_CONTAINER_meta_data_duplicate (mdir);
375 else 361 else
@@ -391,9 +377,9 @@ GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData *mdir
391 */ 377 */
392void 378void
393GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, 379GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld,
394 const struct GNUNET_FS_Uri *uri, 380 const struct GNUNET_FS_Uri *uri,
395 const struct GNUNET_CONTAINER_MetaData *md, 381 const struct GNUNET_CONTAINER_MetaData *md,
396 const void *data) 382 const void *data)
397{ 383{
398 struct GNUNET_FS_Uri *curi; 384 struct GNUNET_FS_Uri *curi;
399 struct BuilderEntry *e; 385 struct BuilderEntry *e;
@@ -409,68 +395,64 @@ GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld,
409 struct GNUNET_CONTAINER_MetaData *meta; 395 struct GNUNET_CONTAINER_MetaData *meta;
410 const struct GNUNET_CONTAINER_MetaData *meta_use; 396 const struct GNUNET_CONTAINER_MetaData *meta_use;
411 397
412 GNUNET_assert (! GNUNET_FS_uri_test_ksk (uri)); 398 GNUNET_assert (!GNUNET_FS_uri_test_ksk (uri));
413 if (NULL != data) 399 if (NULL != data)
400 {
401 GNUNET_assert (!GNUNET_FS_uri_test_sks (uri));
402 if (GNUNET_FS_uri_test_chk (uri))
414 { 403 {
415 GNUNET_assert (! GNUNET_FS_uri_test_sks (uri)); 404 fsize = GNUNET_FS_uri_chk_get_file_size (uri);
416 if (GNUNET_FS_uri_test_chk (uri))
417 {
418 fsize = GNUNET_FS_uri_chk_get_file_size (uri);
419 }
420 else
421 {
422 curi = GNUNET_FS_uri_loc_get_uri (uri);
423 GNUNET_assert (NULL != curi);
424 fsize = GNUNET_FS_uri_chk_get_file_size (curi);
425 GNUNET_FS_uri_destroy (curi);
426 }
427 } 405 }
428 else 406 else
429 { 407 {
430 fsize = 0; /* not given */ 408 curi = GNUNET_FS_uri_loc_get_uri (uri);
409 GNUNET_assert (NULL != curi);
410 fsize = GNUNET_FS_uri_chk_get_file_size (curi);
411 GNUNET_FS_uri_destroy (curi);
431 } 412 }
413 }
414 else
415 {
416 fsize = 0; /* not given */
417 }
432 if (fsize > MAX_INLINE_SIZE) 418 if (fsize > MAX_INLINE_SIZE)
433 fsize = 0; /* too large */ 419 fsize = 0; /* too large */
434 uris = GNUNET_FS_uri_to_string (uri); 420 uris = GNUNET_FS_uri_to_string (uri);
435 slen = strlen (uris) + 1; 421 slen = strlen (uris) + 1;
436 mds = 422 mds = GNUNET_CONTAINER_meta_data_get_serialized_size (md);
437 GNUNET_CONTAINER_meta_data_get_serialized_size (md);
438 meta_use = md; 423 meta_use = md;
439 meta = NULL; 424 meta = NULL;
440 if (fsize > 0) 425 if (fsize > 0)
426 {
427 meta = GNUNET_CONTAINER_meta_data_duplicate (md);
428 GNUNET_CONTAINER_meta_data_insert (meta,
429 "<gnunet>",
430 EXTRACTOR_METATYPE_GNUNET_FULL_DATA,
431 EXTRACTOR_METAFORMAT_BINARY,
432 NULL, data, fsize);
433 mdxs = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
434 if ((slen + sizeof (uint32_t) + mdxs - 1) / DBLOCK_SIZE ==
435 (slen + sizeof (uint32_t) + mds - 1) / DBLOCK_SIZE)
441 { 436 {
442 meta = GNUNET_CONTAINER_meta_data_duplicate (md); 437 /* adding full data would not cause us to cross
443 GNUNET_CONTAINER_meta_data_insert (meta, 438 * additional blocks, so add it! */
444 "<gnunet>", 439 meta_use = meta;
445 EXTRACTOR_METATYPE_GNUNET_FULL_DATA, 440 mds = mdxs;
446 EXTRACTOR_METAFORMAT_BINARY,
447 NULL,
448 data,
449 fsize);
450 mdxs =
451 GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
452 if ( (slen + sizeof (uint32_t) + mdxs - 1) / DBLOCK_SIZE ==
453 (slen + sizeof (uint32_t) + mds - 1) / DBLOCK_SIZE)
454 {
455 /* adding full data would not cause us to cross
456 additional blocks, so add it! */
457 meta_use = meta;
458 mds = mdxs;
459 }
460 } 441 }
442 }
461 443
462 if (mds > GNUNET_MAX_MALLOC_CHECKED / 2) 444 if (mds > GNUNET_MAX_MALLOC_CHECKED / 2)
463 mds = GNUNET_MAX_MALLOC_CHECKED / 2; 445 mds = GNUNET_MAX_MALLOC_CHECKED / 2;
464 e = GNUNET_malloc (sizeof(struct BuilderEntry) + 446 e = GNUNET_malloc (sizeof (struct BuilderEntry) +
465 slen + mds + sizeof (uint32_t)); 447 slen + mds + sizeof (uint32_t));
466 ser = (char*) &e[1]; 448 ser = (char *) &e[1];
467 memcpy (ser, uris, slen); 449 memcpy (ser, uris, slen);
468 GNUNET_free (uris); 450 GNUNET_free (uris);
469 sptr = &ser[slen + sizeof(uint32_t)]; 451 sptr = &ser[slen + sizeof (uint32_t)];
470 ret = GNUNET_CONTAINER_meta_data_serialize (meta_use, 452 ret = GNUNET_CONTAINER_meta_data_serialize (meta_use,
471 &sptr, 453 &sptr,
472 mds, 454 mds,
473 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); 455 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
474 if (NULL != meta) 456 if (NULL != meta)
475 GNUNET_CONTAINER_meta_data_destroy (meta); 457 GNUNET_CONTAINER_meta_data_destroy (meta);
476 if (ret == -1) 458 if (ret == -1)
@@ -492,11 +474,10 @@ GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld,
492 * after alignment to the DBLOCK_SIZE. 474 * after alignment to the DBLOCK_SIZE.
493 */ 475 */
494static size_t 476static size_t
495do_align (size_t start_position, 477do_align (size_t start_position, size_t end_position)
496 size_t end_position)
497{ 478{
498 size_t align; 479 size_t align;
499 480
500 align = (end_position / DBLOCK_SIZE) * DBLOCK_SIZE; 481 align = (end_position / DBLOCK_SIZE) * DBLOCK_SIZE;
501 if ((start_position < align) && (end_position > align)) 482 if ((start_position < align) && (end_position > align))
502 return align + end_position - start_position; 483 return align + end_position - start_position;
@@ -515,9 +496,7 @@ do_align (size_t start_position,
515 */ 496 */
516static void 497static void
517block_align (size_t start, 498block_align (size_t start,
518 unsigned int count, 499 unsigned int count, const size_t * sizes, unsigned int *perm)
519 const size_t *sizes,
520 unsigned int *perm)
521{ 500{
522 unsigned int i; 501 unsigned int i;
523 unsigned int j; 502 unsigned int j;
@@ -531,51 +510,46 @@ block_align (size_t start,
531 510
532 cpos = start; 511 cpos = start;
533 for (i = 0; i < count; i++) 512 for (i = 0; i < count; i++)
513 {
514 start = cpos;
515 badness = 0x7FFFFFFF;
516 best = -1;
517 for (j = i; j < count; j++)
534 { 518 {
535 start = cpos; 519 cval = perm[j];
536 badness = 0x7FFFFFFF; 520 cend = cpos + sizes[cval];
537 best = -1; 521 if (cpos % DBLOCK_SIZE == 0)
538 for (j = i; j < count; j++) 522 {
523 /* prefer placing the largest blocks first */
524 cbad = -(cend % DBLOCK_SIZE);
525 }
526 else
527 {
528 if (cpos / DBLOCK_SIZE == cend / DBLOCK_SIZE)
529 {
530 /* Data fits into the same block! Prefer small left-overs! */
531 cbad = DBLOCK_SIZE - cend % DBLOCK_SIZE;
532 }
533 else
539 { 534 {
540 cval = perm[j]; 535 /* Would have to waste space to re-align, add big factor, this
541 cend = cpos + sizes[cval]; 536 * case is a real loss (proportional to space wasted)! */
542 if (cpos % DBLOCK_SIZE == 0) 537 cbad = DBLOCK_SIZE * (DBLOCK_SIZE - cpos % DBLOCK_SIZE);
543 {
544 /* prefer placing the largest blocks first */
545 cbad = -(cend % DBLOCK_SIZE);
546 }
547 else
548 {
549 if (cpos / DBLOCK_SIZE ==
550 cend / DBLOCK_SIZE)
551 {
552 /* Data fits into the same block! Prefer small left-overs! */
553 cbad =
554 DBLOCK_SIZE - cend % DBLOCK_SIZE;
555 }
556 else
557 {
558 /* Would have to waste space to re-align, add big factor, this
559 case is a real loss (proportional to space wasted)! */
560 cbad =
561 DBLOCK_SIZE * (DBLOCK_SIZE -
562 cpos %
563 DBLOCK_SIZE);
564 }
565 }
566 if (cbad < badness)
567 {
568 best = j;
569 badness = cbad;
570 }
571 } 538 }
572 GNUNET_assert (best != -1); 539 }
573 tmp = perm[i]; 540 if (cbad < badness)
574 perm[i] = perm[best]; 541 {
575 perm[best] = tmp; 542 best = j;
576 cpos += sizes[perm[i]]; 543 badness = cbad;
577 cpos = do_align (start, cpos); 544 }
578 } 545 }
546 GNUNET_assert (best != -1);
547 tmp = perm[i];
548 perm[i] = perm[best];
549 perm[best] = tmp;
550 cpos += sizes[perm[i]];
551 cpos = do_align (start, cpos);
552 }
579} 553}
580 554
581 555
@@ -591,8 +565,7 @@ block_align (size_t start,
591 */ 565 */
592int 566int
593GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, 567GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
594 size_t *rsize, 568 size_t * rsize, void **rdata)
595 void **rdata)
596{ 569{
597 char *data; 570 char *data;
598 char *sptr; 571 char *sptr;
@@ -614,71 +587,65 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
614 perm = NULL; 587 perm = NULL;
615 bes = NULL; 588 bes = NULL;
616 if (0 < bld->count) 589 if (0 < bld->count)
590 {
591 sizes = GNUNET_malloc (bld->count * sizeof (size_t));
592 perm = GNUNET_malloc (bld->count * sizeof (unsigned int));
593 bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *));
594 pos = bld->head;
595 for (i = 0; i < bld->count; i++)
596 {
597 perm[i] = i;
598 bes[i] = pos;
599 sizes[i] = pos->len;
600 pos = pos->next;
601 }
602 block_align (size, bld->count, sizes, perm);
603 /* compute final size with alignment */
604 for (i = 0; i < bld->count; i++)
617 { 605 {
618 sizes = GNUNET_malloc (bld->count * sizeof (size_t)); 606 psize = size;
619 perm = GNUNET_malloc (bld->count * sizeof (unsigned int)); 607 size += sizes[perm[i]];
620 bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *)); 608 size = do_align (psize, size);
621 pos = bld->head;
622 for (i = 0; i < bld->count; i++)
623 {
624 perm[i] = i;
625 bes[i] = pos;
626 sizes[i] = pos->len;
627 pos = pos->next;
628 }
629 block_align (size,
630 bld->count,
631 sizes,
632 perm);
633 /* compute final size with alignment */
634 for (i = 0; i < bld->count; i++)
635 {
636 psize = size;
637 size += sizes[perm[i]];
638 size = do_align (psize, size);
639 }
640 } 609 }
610 }
641 *rsize = size; 611 *rsize = size;
642 data = GNUNET_malloc_large (size); 612 data = GNUNET_malloc_large (size);
643 if (data == NULL) 613 if (data == NULL)
644 { 614 {
645 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 615 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc");
646 "malloc"); 616 *rsize = 0;
647 *rsize = 0; 617 *rdata = NULL;
648 *rdata = NULL; 618 GNUNET_free_non_null (sizes);
649 GNUNET_free_non_null (sizes); 619 GNUNET_free_non_null (perm);
650 GNUNET_free_non_null (perm); 620 GNUNET_free_non_null (bes);
651 GNUNET_free_non_null (bes); 621 return GNUNET_SYSERR;
652 return GNUNET_SYSERR; 622 }
653 }
654 *rdata = data; 623 *rdata = data;
655 memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC)); 624 memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC));
656 off = strlen (GNUNET_DIRECTORY_MAGIC); 625 off = strlen (GNUNET_DIRECTORY_MAGIC);
657 626
658 sptr = &data[off + sizeof (uint32_t)]; 627 sptr = &data[off + sizeof (uint32_t)];
659 ret = GNUNET_CONTAINER_meta_data_serialize (bld->meta, 628 ret = GNUNET_CONTAINER_meta_data_serialize (bld->meta,
660 &sptr, 629 &sptr,
661 size - off - sizeof (uint32_t), 630 size - off - sizeof (uint32_t),
662 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); 631 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
663 GNUNET_assert (ret != -1); 632 GNUNET_assert (ret != -1);
664 big = htonl (ret); 633 big = htonl (ret);
665 memcpy (&data[off], &big, sizeof (uint32_t)); 634 memcpy (&data[off], &big, sizeof (uint32_t));
666 off += sizeof (uint32_t) + ret; 635 off += sizeof (uint32_t) + ret;
667 for (j = 0; j < bld->count; j++) 636 for (j = 0; j < bld->count; j++)
668 { 637 {
669 i = perm[j]; 638 i = perm[j];
670 psize = off; 639 psize = off;
671 off += sizes[i]; 640 off += sizes[i];
672 off = do_align (psize, off); 641 off = do_align (psize, off);
673 memcpy (&data[off - sizes[i]], 642 memcpy (&data[off - sizes[i]], &(bes[i])[1], sizes[i]);
674 &(bes[i])[1], 643 GNUNET_free (bes[i]);
675 sizes[i]); 644 }
676 GNUNET_free (bes[i]);
677 }
678 GNUNET_free_non_null (sizes); 645 GNUNET_free_non_null (sizes);
679 GNUNET_free_non_null (perm); 646 GNUNET_free_non_null (perm);
680 GNUNET_free_non_null (bes); 647 GNUNET_free_non_null (bes);
681 GNUNET_assert (off == size); 648 GNUNET_assert (off == size);
682 GNUNET_CONTAINER_meta_data_destroy (bld->meta); 649 GNUNET_CONTAINER_meta_data_destroy (bld->meta);
683 GNUNET_free (bld); 650 GNUNET_free (bld);
684 return GNUNET_OK; 651 return GNUNET_OK;