sources.c 19 KB
Newer Older
Bernhard Link's avatar
Bernhard Link committed
1
/*  This file is part of "reprepro"
2
 *  Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Bernhard R. Link
3
 *  This program is free software; you can redistribute it and/or modify
4
 *  it under the terms of the GNU General Public License version 2 as
Bernhard Link's avatar
Bernhard Link committed
5
 *  published by the Free Software Foundation.
6 7 8 9 10 11 12 13
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
Bernhard Link's avatar
Bernhard Link committed
14
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1301  USA
15
 */
Bernhard Link's avatar
Bernhard Link committed
16 17
#include <config.h>

18
#include <assert.h>
19
#include <sys/types.h>
Bernhard Link's avatar
Bernhard Link committed
20
#include <errno.h>
Bernhard Link's avatar
Bernhard Link committed
21 22 23 24
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <ctype.h>
25
#include <stdlib.h>
Bernhard Link's avatar
Bernhard Link committed
26
#include "error.h"
27
#include "mprintf.h"
28
#include "strlist.h"
Bernhard Link's avatar
Bernhard Link committed
29 30 31
#include "chunks.h"
#include "sources.h"
#include "names.h"
32
#include "dirs.h"
Bernhard Link's avatar
Bernhard Link committed
33
#include "dpkgversions.h"
34
#include "override.h"
35
#include "tracking.h"
36
#include "signature.h"
37
#include "package.h"
Bernhard Link's avatar
Bernhard Link committed
38

39 40 41 42 43
/* split a "<md5> <size> <filename>" into md5sum and filename */
static retvalue calc_parsefileline(const char *fileline, /*@out@*/char **filename) {
	const char *p, *fn, *fnend;
	char *filen;

44 45
	assert (fileline != NULL);
	if (*fileline == '\0')
46 47 48 49
		return RET_NOTHING;

	/* the md5sums begins after the (perhaps) heading spaces ...  */
	p = fileline;
50
	while (*p != '\0' && (*p == ' ' || *p == '\t'))
51
		p++;
52
	if (*p == '\0')
53 54
		return RET_NOTHING;
	/* ... and ends with the following spaces. */
55
	while (*p != '\0' && !(*p == ' ' || *p == '\t'))
56
		p++;
57
	if (*p == '\0') {
58 59 60 61
		fprintf(stderr, "Expecting more data after md5sum!\n");
		return RET_ERROR;
	}
	/* Then the size of the file is expected: */
62
	while ((*p == ' ' || *p == '\t'))
63
		p++;
64
	while (*p !='\0' && !(*p == ' ' || *p == '\t'))
65
		p++;
66
	if (*p == '\0') {
67 68 69 70 71
		fprintf(stderr, "Expecting more data after size!\n");
		return RET_ERROR;
	}
	/* Then the filename */
	fn = p;
72
	while ((*fn == ' ' || *fn == '\t'))
73 74
		fn++;
	fnend = fn;
75
	while (*fnend != '\0' && !(*fnend == ' ' || *fnend == '\t'))
76 77 78
		fnend++;

	filen = strndup(fn, fnend-fn);
79
	if (FAILEDTOALLOC(filen))
80 81 82 83
		return RET_ERROR_OOM;
	*filename = filen;
	return RET_OK;
}
Bernhard Link's avatar
Bernhard Link committed
84

85
static retvalue getBasenames(const struct strlist *filelines, /*@out@*/struct strlist *basenames) {
86 87 88
	int i;
	retvalue r;

89
	assert (filelines != NULL && basenames != NULL);
90

91 92
	r = strlist_init_n(filelines->count, basenames);
	if (RET_WAS_ERROR(r))
93 94
		return r;
	r = RET_NOTHING;
95
	for (i = 0 ; i < filelines->count ; i++) {
96
		char *basefilename;
97
		const char *fileline = filelines->values[i];
98

99
		r = calc_parsefileline(fileline, &basefilename);
100
		if (r == RET_NOTHING) {
Bernhard Link's avatar
Bernhard Link committed
101 102 103 104
			fprintf(stderr, "Malformed Files: line '%s'!\n",
					fileline);
			r = RET_ERROR;
		}
105
		if (RET_WAS_ERROR(r))
106 107
			break;

108
		r = strlist_add(basenames, basefilename);
109
		if (RET_WAS_ERROR(r)) {
110 111 112 113
			break;
		}
		r = RET_OK;
	}
114
	if (RET_WAS_ERROR(r)) {
115
		strlist_done(basenames);
116
	} else {
117
		assert (filelines->count == basenames->count);
118 119 120 121
	}
	return r;
}

122
retvalue sources_getversion(const char *control, char **version) {
123 124
	retvalue r;

125 126
	r = chunk_getvalue(control, "Version", version);
	if (RET_WAS_ERROR(r))
127
		return r;
128 129 130
	if (r == RET_NOTHING) {
		fprintf(stderr, "Missing 'Version' field in chunk:'%s'\n",
				control);
131 132 133 134
		return RET_ERROR;
	}
	return r;
}
135

136 137 138 139 140
retvalue sources_getarchitecture(UNUSED(const char *chunk), architecture_t *architecture_p) {
	*architecture_p = architecture_source;
	return RET_OK;
}

141
retvalue sources_getinstalldata(const struct target *t, struct package *package, char **control, struct strlist *filekeys, struct checksumsarray *origfiles) {
142
	retvalue r;
143
	char *origdirectory, *directory, *mychunk;
144 145
	struct strlist myfilekeys;
	struct strlist filelines[cs_hashCOUNT];
146
	struct checksumsarray files;
147
	enum checksumtype cs;
148
	bool gothash = false;
149
	const char *chunk = package->control;
150

151
	assert (package->architecture == architecture_source);
152

153 154
	for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
		assert (source_checksum_names[cs] != NULL);
155 156
		r = chunk_getextralinelist(chunk, source_checksum_names[cs],
				&filelines[cs]);
157 158 159
		if (r == RET_NOTHING)
			strlist_init(&filelines[cs]);
		else if (RET_WAS_ERROR(r)) {
160
			while (cs-- > cs_md5sum) {
161 162 163
				strlist_done(&filelines[cs]);
			}
			return r;
164 165 166 167 168 169 170 171 172 173
		} else
			gothash = true;
	}
	if (!gothash) {
		fprintf(stderr,
"Missing 'Files' (or 'SHA1' or ...)  entry in '%s'!\n",
				chunk);
		for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++)
			strlist_done(&filelines[cs]);
		return RET_ERROR;
174
	}
175
	r = checksumsarray_parse(&files, filelines, package->name);
176
	for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
177
		strlist_done(&filelines[cs]);
178
	}
179
	if (RET_WAS_ERROR(r))
180 181 182
		return r;

	r = chunk_getvalue(chunk, "Directory", &origdirectory);
183
	if (r == RET_NOTHING) {
184
/* Flat repositories can come without this, TODO: add warnings in other cases
185
		fprintf(stderr, "Missing 'Directory' entry in '%s'!\n", chunk);
186
		r = RET_ERROR;
187 188
*/
		origdirectory = strdup(".");
189
		if (FAILEDTOALLOC(origdirectory))
190
			r = RET_ERROR_OOM;
191
	}
192
	if (RET_WAS_ERROR(r)) {
193
		checksumsarray_done(&files);
194
		return r;
195 196
	}

197
	r = propersourcename(package->name);
198 199
	assert (r != RET_NOTHING);
	if (RET_IS_OK(r))
200
		r = properfilenames(&files.names);
201 202
	if (RET_WAS_ERROR(r)) {
		fprintf(stderr,
203
"Forbidden characters in source package '%s'!\n", package->name);
204
		free(origdirectory);
205
		checksumsarray_done(&files);
206
		return r;
207
	}
208

209
	directory = calc_sourcedir(t->component, package->name);
210
	if (FAILEDTOALLOC(directory))
211 212 213
		r = RET_ERROR_OOM;
	else
		r = calc_dirconcats(directory, &files.names, &myfilekeys);
214
	if (RET_WAS_ERROR(r)) {
215
		free(directory);
216
		free(origdirectory);
217
		checksumsarray_done(&files);
218 219
		return r;
	}
220
	r = calc_inplacedirconcats(origdirectory, &files.names);
221
	free(origdirectory);
222
	if (!RET_WAS_ERROR(r)) {
223 224
		char *n;

225
		n = chunk_normalize(chunk, "Package", package->name);
226 227 228 229 230 231
		if (FAILEDTOALLOC(n))
			mychunk = NULL;
		else
			mychunk = chunk_replacefield(n,
					"Directory", directory, true);
		free(n);
232
		if (FAILEDTOALLOC(mychunk))
233 234 235
			r = RET_ERROR_OOM;
	}
	free(directory);
236
	if (RET_WAS_ERROR(r)) {
237 238 239
		strlist_done(&myfilekeys);
		checksumsarray_done(&files);
		return r;
240
	}
241 242 243 244
	*control = mychunk;
	strlist_move(filekeys, &myfilekeys);
	checksumsarray_move(origfiles, &files);
	return RET_OK;
245 246
}

247
retvalue sources_getfilekeys(const char *chunk, struct strlist *filekeys) {
248
	char *origdirectory;
249
	struct strlist basenames;
250
	retvalue r;
251
	struct strlist filelines;
252

253 254 255

	/* Read the directory given there */
	r = chunk_getvalue(chunk, "Directory", &origdirectory);
256
	if (r == RET_NOTHING) {
257
		//TODO: check if it is even text and do not print
258
		//of looking binary??
259 260
		fprintf(stderr, "Does not look like source control: '%s'\n",
				chunk);
261 262
		return RET_ERROR;
	}
263
	if (RET_WAS_ERROR(r))
264 265
		return r;

266
	r = chunk_getextralinelist(chunk, "Files", &filelines);
267
	if (r == RET_NOTHING) {
268 269
		//TODO: check if it is even text and do not print
		//of looking binary??
270 271
		fprintf(stderr, "Does not look like source control: '%s'\n",
				chunk);
272 273
		r = RET_ERROR;
	}
274
	if (RET_WAS_ERROR(r)) {
275 276 277 278 279
		free(origdirectory);
		return r;
	}
	r = getBasenames(&filelines, &basenames);
	strlist_done(&filelines);
280
	if (RET_WAS_ERROR(r)) {
281
		free(origdirectory);
282 283
		return r;
	}
284 285 286 287

	r = calc_dirconcats(origdirectory, &basenames, filekeys);
	free(origdirectory);
	strlist_done(&basenames);
288
	return r;
289
}
290

291 292 293 294
retvalue sources_getchecksums(const char *chunk, struct checksumsarray *out) {
	char *origdirectory;
	struct checksumsarray a;
	retvalue r;
295 296
	struct strlist filelines[cs_hashCOUNT];
	enum checksumtype cs;
297 298 299

	/* Read the directory given there */
	r = chunk_getvalue(chunk, "Directory", &origdirectory);
300
	if (!RET_IS_OK(r))
301 302
		return r;

303 304
	for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
		assert (source_checksum_names[cs] != NULL);
305 306
		r = chunk_getextralinelist(chunk, source_checksum_names[cs],
				&filelines[cs]);
307 308
		if (r == RET_NOTHING) {
			if (cs == cs_md5sum) {
309
				fprintf(stderr,
310 311
"Missing 'Files' entry in '%s'!\n",
						chunk);
312 313 314 315
				r = RET_ERROR;
			} else
				strlist_init(&filelines[cs]);
		}
316 317
		if (RET_WAS_ERROR(r)) {
			while (cs-- > cs_md5sum) {
318 319 320 321 322 323 324
				strlist_done(&filelines[cs]);
			}
			free(origdirectory);
			return r;
		}
	}
	r = checksumsarray_parse(&a, filelines, "source chunk");
325
	for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
326
		strlist_done(&filelines[cs]);
327
	}
328
	if (RET_WAS_ERROR(r)) {
329 330 331
		free(origdirectory);
		return r;
	}
332

333 334
	r = calc_inplacedirconcats(origdirectory, &a.names);
	free(origdirectory);
335
	if (RET_WAS_ERROR(r)) {
336 337 338 339 340 341 342
		checksumsarray_done(&a);
		return r;
	}
	checksumsarray_move(out, &a);
	return RET_OK;
}

343
retvalue sources_doreoverride(const struct target *target, const char *packagename, const char *controlchunk, /*@out@*/char **newcontrolchunk) {
344
	const struct overridedata *o;
345 346
	struct fieldtoadd *fields;
	char *newchunk;
347
	retvalue r;
348

349
	if (interrupted())
350
		return RET_ERROR_INTERRUPTED;
351

352
	o = override_search(target->distribution->overrides.dsc, packagename);
353
	if (o == NULL)
354 355
		return RET_NOTHING;

356
	r = override_allreplacefields(o, &fields);
357
	if (!RET_IS_OK(r))
358
		return r;
359 360
	newchunk = chunk_replacefields(controlchunk, fields,
			"Directory", true);
361
	addfield_free(fields);
362
	if (FAILEDTOALLOC(newchunk))
363 364 365 366
		return RET_ERROR_OOM;
	*newcontrolchunk = newchunk;
	return RET_OK;
}
367

368
retvalue sources_retrack(const char *sourcename, const char *chunk, trackingdb tracks) {
369 370 371 372
	retvalue r;
	char *sourceversion;
	struct trackedpackage *pkg;
	struct strlist filekeys;
Bernhard Link's avatar
Bernhard Link committed
373
	int i;
374

375
	//TODO: eliminate duplicate code!
376 377
	assert(sourcename!=NULL);

378
	if (interrupted())
379
		return RET_ERROR_INTERRUPTED;
380

381 382 383 384
	r = chunk_getvalue(chunk, "Version", &sourceversion);
	if (r == RET_NOTHING) {
		fprintf(stderr, "Missing 'Version' field in chunk:'%s'\n",
				chunk);
385 386
		r = RET_ERROR;
	}
387
	if (RET_WAS_ERROR(r)) {
388 389 390
		return r;
	}

391
	r = sources_getfilekeys(chunk, &filekeys);
392
	if (r == RET_NOTHING) {
Bernhard Link's avatar
Bernhard Link committed
393
		fprintf(stderr, "Malformed source control:'%s'\n", chunk);
394 395
		r = RET_ERROR;
	}
396
	if (RET_WAS_ERROR(r)) {
397 398 399 400
		free(sourceversion);
		return r;
	}

401
	r = tracking_getornew(tracks, sourcename, sourceversion, &pkg);
402
	free(sourceversion);
403
	if (RET_WAS_ERROR(r)) {
404 405 406 407
		strlist_done(&filekeys);
		return r;
	}

Bernhard Link's avatar
Bernhard Link committed
408 409 410
	// TODO: error handling is suboptimal here.
	//  is there a way to again remove old additions (esp. references)
	//  where something fails?
411
	for (i = 0 ; i < filekeys.count ; i++) {
Bernhard Link's avatar
Bernhard Link committed
412
		r = trackedpackage_addfilekey(tracks, pkg,
413
				ft_SOURCE, filekeys.values[i], true);
Bernhard Link's avatar
Bernhard Link committed
414
		filekeys.values[i] = NULL;
415
		if (RET_WAS_ERROR(r)) {
Bernhard Link's avatar
Bernhard Link committed
416 417 418 419
			strlist_done(&filekeys);
			trackedpackage_free(pkg);
			return r;
		}
420
	}
Bernhard Link's avatar
Bernhard Link committed
421
	strlist_done(&filekeys);
422
	return tracking_save(tracks, pkg);
423 424
}

425
retvalue sources_getsourceandversion(const char *chunk, const char *packagename, char **source, char **version) {
426 427 428 429
	retvalue r;
	char *sourceversion;
	char *sourcename;

430
	//TODO: eliminate duplicate code!
431 432
	assert(packagename!=NULL);

433 434 435 436
	r = chunk_getvalue(chunk, "Version", &sourceversion);
	if (r == RET_NOTHING) {
		fprintf(stderr, "Missing 'Version' field in chunk:'%s'\n",
				chunk);
437 438
		r = RET_ERROR;
	}
439
	if (RET_WAS_ERROR(r)) {
440 441 442
		return r;
	}
	sourcename = strdup(packagename);
443
	if (FAILEDTOALLOC(sourcename)) {
444 445 446 447 448 449 450
		free(sourceversion);
		return RET_ERROR_OOM;
	}
	*source = sourcename;
	*version = sourceversion;
	return RET_OK;
}
451 452 453

/****************************************************************/

454
static inline retvalue getvalue(const char *filename, const char *chunk, const char *field, char **value) {
455 456
	retvalue r;

457 458 459 460
	r = chunk_getvalue(chunk, field, value);
	if (r == RET_NOTHING) {
		fprintf(stderr, "Missing '%s' field in %s!\n",
				field, filename);
461 462 463 464 465
		r = RET_ERROR;
	}
	return r;
}

466
static inline retvalue checkvalue(const char *filename, const char *chunk, const char *field) {
467 468
	retvalue r;

469 470 471 472
	r = chunk_checkfield(chunk, field);
	if (r == RET_NOTHING) {
		fprintf(stderr, "Cannot find '%s' field in %s!\n",
				field, filename);
473 474 475 476 477
		r = RET_ERROR;
	}
	return r;
}

478
static inline retvalue getvalue_n(const char *chunk, const char *field, char **value) {
479 480
	retvalue r;

481 482
	r = chunk_getvalue(chunk, field, value);
	if (r == RET_NOTHING) {
483 484 485 486 487
		*value = NULL;
	}
	return r;
}

488
retvalue sources_readdsc(struct dsc_headers *dsc, const char *filename, const char *filenametoshow, bool *broken) {
489
	retvalue r;
490 491
	struct strlist filelines[cs_hashCOUNT];
	enum checksumtype cs;
492

493
	r = signature_readsignedchunk(filename, filenametoshow,
494
			&dsc->control, NULL, broken);
495
	if (RET_WAS_ERROR(r)) {
496 497
		return r;
	}
498
	if (verbose > 100) {
499 500
		fprintf(stderr, "Extracted control chunk from '%s': '%s'\n",
				filenametoshow, dsc->control);
501 502 503 504
	}

	/* first look for fields that should be there */

505
	r = chunk_getname(dsc->control, "Source", &dsc->name, false);
506 507 508
	if (r == RET_NOTHING) {
		fprintf(stderr, "Missing 'Source' field in %s!\n",
				filenametoshow);
509 510
		return RET_ERROR;
	}
511
	if (RET_WAS_ERROR(r))
512 513
		return r;

514
	/* This is needed and cannot be ignored unless
515
	 * sources_complete is changed to not need it */
516
	r = checkvalue(filenametoshow, dsc->control, "Format");
517
	if (RET_WAS_ERROR(r))
518 519
		return r;

520
	r = checkvalue(filenametoshow, dsc->control, "Maintainer");
521
	if (RET_WAS_ERROR(r))
522 523
		return r;

524
	r = getvalue(filenametoshow, dsc->control, "Version", &dsc->version);
525
	if (RET_WAS_ERROR(r))
526 527
		return r;

528
	r = getvalue_n(dsc->control, SECTION_FIELDNAME, &dsc->section);
529
	if (RET_WAS_ERROR(r))
530
		return r;
531
	r = getvalue_n(dsc->control, PRIORITY_FIELDNAME, &dsc->priority);
532
	if (RET_WAS_ERROR(r))
533
		return r;
534

535 536
	for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
		assert (source_checksum_names[cs] != NULL);
537 538
		r = chunk_getextralinelist(dsc->control,
				source_checksum_names[cs], &filelines[cs]);
539 540
		if (r == RET_NOTHING) {
			if (cs == cs_md5sum) {
541
				fprintf(stderr,
542 543
"Missing 'Files' field in '%s'!\n",
					filenametoshow);
544 545 546 547
				r = RET_ERROR;
			} else
				strlist_init(&filelines[cs]);
		}
548 549
		if (RET_WAS_ERROR(r)) {
			while (cs-- > cs_md5sum) {
550 551 552 553 554 555
				strlist_done(&filelines[cs]);
			}
			return r;
		}
	}
	r = checksumsarray_parse(&dsc->files, filelines, filenametoshow);
556
	for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
557
		strlist_done(&filelines[cs]);
558
	}
559 560 561 562 563 564 565
	return r;
}

void sources_done(struct dsc_headers *dsc) {
	free(dsc->name);
	free(dsc->version);
	free(dsc->control);
566
	checksumsarray_done(&dsc->files);
567 568 569 570
	free(dsc->section);
	free(dsc->priority);
}

571
retvalue sources_complete(const struct dsc_headers *dsc, const char *directory, const struct overridedata *override, const char *section, const char *priority, char **newcontrol) {
572 573
	retvalue r;
	struct fieldtoadd *replace;
574
	char *newchunk, *newchunk2;
575
	char *newfilelines, *newsha1lines, *newsha256lines;
576

577
	assert(section != NULL && priority != NULL);
578

579
	newchunk2 = chunk_normalize(dsc->control, "Package", dsc->name);
580
	if (FAILEDTOALLOC(newchunk2))
581 582
		return RET_ERROR_OOM;

583 584
	r = checksumsarray_genfilelist(&dsc->files,
			&newfilelines, &newsha1lines, &newsha256lines);
585
	if (RET_WAS_ERROR(r)) {
586
		free(newchunk2);
587
		return r;
588
	}
589
	assert (newfilelines != NULL);
590
	replace = aodfield_new("Checksums-Sha256", newsha256lines, NULL);
591
	if (!FAILEDTOALLOC(replace))
592
		replace = aodfield_new("Checksums-Sha1", newsha1lines, replace);
593 594
	if (!FAILEDTOALLOC(replace))
		replace = deletefield_new("Source", replace);
595
	if (!FAILEDTOALLOC(replace))
596
		replace = addfield_new("Files", newfilelines, replace);
597 598 599 600 601 602 603 604 605 606 607
	if (!FAILEDTOALLOC(replace))
		replace = addfield_new("Directory", directory, replace);
	if (!FAILEDTOALLOC(replace))
		replace = deletefield_new("Status", replace);
	if (!FAILEDTOALLOC(replace))
		replace = addfield_new(SECTION_FIELDNAME, section, replace);
	if (!FAILEDTOALLOC(replace))
		replace = addfield_new(PRIORITY_FIELDNAME, priority, replace);
	if (!FAILEDTOALLOC(replace))
		replace = override_addreplacefields(override, replace);
	if (FAILEDTOALLOC(replace)) {
608 609
		free(newsha256lines);
		free(newsha1lines);
610 611 612 613 614
		free(newfilelines);
		free(newchunk2);
		return RET_ERROR_OOM;
	}

615
	newchunk  = chunk_replacefields(newchunk2, replace, "Files", true);
616 617
	free(newsha256lines);
	free(newsha1lines);
618 619 620
	free(newfilelines);
	free(newchunk2);
	addfield_free(replace);
621
	if (FAILEDTOALLOC(newchunk)) {
622 623 624
		return RET_ERROR_OOM;
	}

625
	*newcontrol = newchunk;
626 627 628 629

	return RET_OK;
}

630 631 632 633 634 635 636 637 638 639 640 641
/* update Checksums */
retvalue sources_complete_checksums(const char *chunk, const struct strlist *filekeys, struct checksums **c, char **out) {
	struct fieldtoadd *replace;
	char *newchunk;
	char *newfilelines, *newsha1lines, *newsha256lines;
	struct checksumsarray checksums;
	retvalue r;
	int i;

	/* fake a checksumarray... */
	checksums.checksums = c;
	checksums.names.count = filekeys->count;
642 643
	checksums.names.values = nzNEW(filekeys->count, char *);
	if (FAILEDTOALLOC(checksums.names.values))
644
		return RET_ERROR_OOM;
645
	for (i = 0 ; i < filekeys->count ; i++) {
646 647 648 649 650 651
		checksums.names.values[i] = (char*)
			dirs_basename(filekeys->values[i]);
	}

	r = checksumsarray_genfilelist(&checksums,
			&newfilelines, &newsha1lines, &newsha256lines);
652
	free(checksums.names.values);
653 654 655
	if (RET_WAS_ERROR(r))
		return r;
	assert (newfilelines != NULL);
656
	replace = aodfield_new("Checksums-Sha256", newsha256lines, NULL);
657
	if (!FAILEDTOALLOC(replace))
658
		replace = aodfield_new("Checksums-Sha1", newsha1lines, replace);
659
	if (!FAILEDTOALLOC(replace))
660
		replace = addfield_new("Files", newfilelines, replace);
661
	if (FAILEDTOALLOC(replace)) {
662 663 664 665 666
		free(newsha256lines);
		free(newsha1lines);
		free(newfilelines);
		return RET_ERROR_OOM;
	}
667
	newchunk = chunk_replacefields(chunk, replace, "Files", true);
668 669 670 671
	free(newsha256lines);
	free(newsha1lines);
	free(newfilelines);
	addfield_free(replace);
672
	if (FAILEDTOALLOC(newchunk))
673 674 675 676 677 678
		return RET_ERROR_OOM;

	*out = newchunk;
	return RET_OK;
}

679 680
char *calc_source_basename(const char *name, const char *version) {
	const char *v = strchr(version, ':');
681
	if (v != NULL)
682 683 684 685 686 687 688 689
		v++;
	else
		v = version;
	return mprintf("%s_%s.dsc", name, v);
}

char *calc_sourcedir(component_t component, const char *sourcename) {

690
	assert (*sourcename != '\0');
691

692 693
	if (sourcename[0] == 'l' && sourcename[1] == 'i' &&
			sourcename[2] == 'b' && sourcename[3] != '\0')
694 695 696
		return mprintf("pool/%s/lib%c/%s",
				atoms_components[component],
				sourcename[3], sourcename);
697
	else if (*sourcename != '\0')
698 699 700 701 702 703 704 705
		return mprintf("pool/%s/%c/%s",
				atoms_components[component],
				sourcename[0], sourcename);
	else
		return NULL;
}

char *calc_filekey(component_t component, const char *sourcename, const char *filename) {
706 707
	if (sourcename[0] == 'l' && sourcename[1] == 'i' &&
			sourcename[2] == 'b' && sourcename[3] != '\0')
708 709 710
		return mprintf("pool/%s/lib%c/%s/%s",
				atoms_components[component],
				sourcename[3], sourcename, filename);
711
	else if (*sourcename != '\0')
712 713 714 715 716 717 718
		return mprintf("pool/%s/%c/%s/%s",
				atoms_components[component],
				sourcename[0], sourcename, filename);
	else
		return NULL;
}

719
char *calc_byhanddir(component_t component, const char *sourcename, const char *version) {
720 721
	if (sourcename[0] == 'l' && sourcename[1] == 'i' &&
			sourcename[2] == 'b' && sourcename[3] != '\0')
722 723 724 725
		return mprintf("pool/%s/lib%c/%s/%s_%s_byhand",
				atoms_components[component],
				sourcename[3], sourcename,
				sourcename, version);
726
	else if (*sourcename != '\0')
727 728 729 730 731 732 733
		return mprintf("pool/%s/%c/%s/%s_%s_byhand",
				atoms_components[component],
				sourcename[0], sourcename,
				sourcename, version);
	else
		return NULL;
}