upgradelist.c 19.8 KB
Newer Older
Bernhard Link's avatar
Bernhard Link committed
1
/*  This file is part of "reprepro"
2
 *  Copyright (C) 2004,2005,2006,2007,2008,2016 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 16 17
 */
#include <config.h>

18
#include <stdlib.h>
19 20
#include <string.h>
#include <stdio.h>
Bernhard Link's avatar
Bernhard Link committed
21
#include <stdlib.h>
22 23 24
#include <assert.h>

#include "error.h"
25
#include "ignore.h"
26
#include "strlist.h"
27
#include "indexfile.h"
28
#include "dpkgversions.h"
29
#include "target.h"
30
#include "files.h"
31
#include "descriptions.h"
32 33
#include "package.h"
#include "upgradelist.h"
34

35 36
struct package_data {
	struct package_data *next;
37 38
	/* the name of the package: */
	char *name;
39
	/* the version in our repository:
Bernhard Link's avatar
Bernhard Link committed
40
	 * NULL means not yet in the archive */
41
	char *version_in_use;
42
	/* the most recent version we found
43
	 * (either is version_in_use or version_new)*/
Bernhard Link's avatar
Bernhard Link committed
44
	/*@dependent@*/const char *version;
45

46 47 48
	/* if this is != 0, package will be deleted afterwards,
	 * (or new version simply ignored if it is not yet in the
	 * archive) */
49
	bool deleted;
50

51 52 53 54
	/* The most recent version we found upstream:
	 * NULL means nothing found. */
	char *new_version;
	/* where the recent version comes from: */
55
	/*@dependent@*/void *privdata;
56

57
	/* the new control-chunk for the package to go in
58
	 * non-NULL if new_version && newversion == version_in_use */
59
	char *new_control;
60
	/* the list of files that will belong to this:
61
	 * same validity */
62
	struct strlist new_filekeys;
63
	struct checksumsarray new_origfiles;
64 65
	/* to destinguish arch all from not arch all */
	architecture_t architecture;
66
};
67

68
struct upgradelist {
Bernhard Link's avatar
Bernhard Link committed
69
	/*@dependent@*/struct target *target;
70
	struct package_data *list;
71
	/* package the next package will most probably be after.
72
	 * (NULL=before start of list) */
Bernhard Link's avatar
Bernhard Link committed
73
	/*@null@*//*@dependent@*/struct package_data *last;
74
	/* internal...*/
75 76
};

Bernhard Link's avatar
Bernhard Link committed
77
static void package_data_free(/*@only@*/struct package_data *data){
78
	if (data == NULL)
79 80 81 82 83 84
		return;
	free(data->name);
	free(data->version_in_use);
	free(data->new_version);
	//free(data->new_from);
	free(data->new_control);
85
	strlist_done(&data->new_filekeys);
86
	checksumsarray_done(&data->new_origfiles);
87 88 89
	free(data);
}

Bernhard Link's avatar
Bernhard Link committed
90 91 92
/* This is called before any package lists are read.
 * It is called once for every package we already have in this target.
 * upgrade->list points to the first in the sorted list,
93
 * upgrade->last to the last one inserted */
94
static retvalue save_package_version(struct upgradelist *upgrade, struct package *pkg) {
95
	retvalue r;
96
	struct package_data *package;
97

98
	r = package_getversion(pkg);
99
	if (RET_WAS_ERROR(r))
100 101
		return r;

102
	package = zNEW(struct package_data);
103
	if (FAILEDTOALLOC(package))
104 105
		return RET_ERROR_OOM;

106
	package->privdata = NULL;
107
	package->name = strdup(pkg->name);
108
	if (FAILEDTOALLOC(package->name)) {
109 110 111
		free(package);
		return RET_ERROR_OOM;
	}
112 113 114 115 116 117
	package->version_in_use = package_dupversion(pkg);
	if (FAILEDTOALLOC(package->version_in_use)) {
		free(package->name);
		free(package);
		return RET_ERROR_OOM;
	}
118
	package->version = package->version_in_use;
119

120
	if (upgrade->list == NULL) {
121
		/* first package to add: */
122
		upgrade->list = package;
123
		upgrade->last = package;
124
	} else {
125
		if (strcmp(pkg->name, upgrade->last->name) > 0) {
126 127
			upgrade->last->next = package;
			upgrade->last = package;
128 129 130 131
		} else {
			/* this should only happen if the underlying
			 * database-method get changed, so just throwing
			 * out here */
Bernhard Link's avatar
Bernhard Link committed
132
			fprintf(stderr, "Package database is not sorted!!!\n");
133
			assert(false);
Bernhard Link's avatar
Bernhard Link committed
134
			exit(EXIT_FAILURE);
135 136 137 138 139
		}
	}

	return RET_OK;
}
140

141
retvalue upgradelist_initialize(struct upgradelist **ul, struct target *t) {
142
	struct upgradelist *upgrade;
143
	retvalue r, r2;
144
	struct package_cursor iterator;
145

146 147
	upgrade = zNEW(struct upgradelist);
	if (FAILEDTOALLOC(upgrade))
148 149
		return RET_ERROR_OOM;

150
	upgrade->target = t;
151

152
	/* Beginn with the packages currently in the archive */
153

154
	r = package_openiterator(t, READONLY, &iterator);
155
	if (RET_WAS_ERROR(r)) {
156
		upgradelist_free(upgrade);
157 158
		return r;
	}
159
	while (package_next(&iterator)) {
160
		r2 = save_package_version(upgrade, &iterator.current);
161 162
		RET_UPDATE(r, r2);
		if (RET_WAS_ERROR(r2))
163 164
			break;
	}
165
	r2 = package_closeiterator(&iterator);
166
	RET_UPDATE(r, r2);
167

168
	if (RET_WAS_ERROR(r)) {
169
		upgradelist_free(upgrade);
170 171 172 173 174 175 176 177 178
		return r;
	}

	upgrade->last = NULL;

	*ul = upgrade;
	return RET_OK;
}

179
void upgradelist_free(struct upgradelist *upgrade) {
180
	struct package_data *l;
181

182
	if (upgrade == NULL)
183
		return;
184 185

	l = upgrade->list;
186
	while (l != NULL) {
187
		struct package_data *n = l->next;
188 189 190
		package_data_free(l);
		l = n;
	}
191

192
	free(upgrade);
193
	return;
194 195
}

196 197
static retvalue upgradelist_trypackage(struct upgradelist *upgrade, void *privdata, upgrade_decide_function *predecide, void *predecide_data, struct package *package) {
	char *version;
198 199
	retvalue r;
	upgrade_decision decision;
200
	struct package_data *current, *insertafter;
201

202 203

	if (package->architecture == architecture_all) {
204
		if (upgrade->target->packagetype == pt_dsc) {
205 206 207 208 209 210 211
			fputs("Internal error: trying to put binary ('all')"
					" package into source architecture!\n",
					stderr);
			return RET_ERROR_INTERNAL;
		}
	}

212 213 214 215
	version = package_dupversion(package);
	if (FAILEDTOALLOC(version))
		return RET_ERROR_OOM;

216 217 218
	/* insertafter = NULL will mean insert before list */
	insertafter = upgrade->last;
	/* the next one to test, current = NULL will mean not found */
219
	if (insertafter != NULL)
220 221 222 223
		current = insertafter->next;
	else
		current = upgrade->list;

224 225 226
	/* the algorithm assumes almost all packages are feed in
	 * alphabetically. So the next package will likely be quite
	 * after the last one. Otherwise we walk down the long list
227
	 * again and again... and again... and even some more...*/
228

229
	while (true) {
230
		int cmp;
231

232 233
		assert (insertafter == NULL || insertafter->next == current);
		assert (insertafter != NULL || current == upgrade->list);
234

235
		if (current == NULL)
236
			cmp = -1; /* every package is before the end of list */
237
		else
238
			cmp = strcmp(package->name, current->name);
239

240
		if (cmp == 0)
241 242
			break;

243
		if (cmp < 0) {
244 245
			int precmp;

246
			if (insertafter == NULL) {
247 248
				/* if we are before the first
				 * package, add us there...*/
249
				current = NULL;
250 251
				break;
			}
252
			// I only hope no one creates indices anti-sorted:
253
			precmp = strcmp(package->name, insertafter->name);
254
			if (precmp == 0) {
255 256
				current = insertafter;
				break;
257
			} else if (precmp < 0) {
258
				/* restart at the beginning: */
259 260
				current = upgrade->list;
				insertafter = NULL;
261 262
				if (verbose > 10) {
					fprintf(stderr, "restarting search...");
263 264
				}
				continue;
265
			} else { // precmp > 0
266 267 268
				/* insert after insertafter: */
				current = NULL;
				break;
269
			}
270
			assert ("This is not reached" == NULL);
271
		}
272
		/* cmp > 0 : may come later... */
273
		assert (current != NULL);
274 275
		insertafter = current;
		current = current->next;
276
		if (current == NULL) {
277
			/* add behind insertafter at end of list */
278 279 280 281
			break;
		}
		/* otherwise repeat until place found */
	}
282
	if (current == NULL) {
283
		/* adding a package not yet known */
284
		struct package_data *new;
285
		char *newcontrol;
286

287
		decision = predecide(predecide_data, upgrade->target,
288
				package, NULL);
289
		if (decision != UD_UPGRADE) {
290
			upgrade->last = insertafter;
291 292 293
			if (decision == UD_LOUDNO)
				fprintf(stderr,
"Loudly rejecting '%s' '%s' to enter '%s'!\n",
294
						package->name, version,
295
						upgrade->target->identifier);
296
			free(version);
297
			return (decision==UD_ERROR)?RET_ERROR:RET_NOTHING;
298 299
		}

300 301
		new = zNEW(struct package_data);
		if (FAILEDTOALLOC(new)) {
302 303 304
			free(version);
			return RET_ERROR_OOM;
		}
305
		new->deleted = false; //to be sure...
306
		new->privdata = privdata;
307 308 309 310 311 312
		new->name = strdup(package->name);
		if (FAILEDTOALLOC(new->name)) {
			free(version);
			free(new);
			return RET_ERROR_OOM;
		}
313 314
		new->new_version = version;
		new->version = version;
315
		new->architecture = package->architecture;
316
		version = NULL; //to be sure...
317
		r = upgrade->target->getinstalldata(upgrade->target,
318
				package,
319
				&new->new_control, &new->new_filekeys,
320
				&new->new_origfiles);
321
		if (RET_WAS_ERROR(r)) {
322
			package_data_free(new);
323
			return r;
324
		}
325 326 327
		/* apply override data */
		r = upgrade->target->doreoverride(upgrade->target,
				new->name, new->new_control, &newcontrol);
328
		if (RET_WAS_ERROR(r)) {
329 330 331
			package_data_free(new);
			return r;
		}
332
		if (RET_IS_OK(r)) {
333 334 335
			free(new->new_control);
			new->new_control = newcontrol;
		}
336
		if (insertafter != NULL) {
337 338
			new->next = insertafter->next;
			insertafter->next = new;
339
		} else {
340 341
			new->next = upgrade->list;
			upgrade->list = new;
342
		}
343
		upgrade->last = new;
344 345
	} else {
		/* The package already exists: */
346
		char *control, *newcontrol;
347 348
		struct strlist files;
		struct checksumsarray origfiles;
349
		int versioncmp;
350

351
		upgrade->last = current;
352

353 354
		r = dpkgversions_cmp(version, current->version, &versioncmp);
		if (RET_WAS_ERROR(r)) {
355 356 357
			free(version);
			return r;
		}
358
		if (versioncmp <= 0 && !current->deleted) {
359 360 361 362
			/* there already is a newer version, so
			 * doing nothing but perhaps updating what
			 * versions are around, when we are newer
			 * than yet known candidates... */
363 364
			int c = 0;

365
			if (current->new_version == current->version)
366
				c =versioncmp;
367
			else if (current->new_version == NULL)
368 369
				c = 1;
			else (void)dpkgversions_cmp(version,
370
					       current->new_version, &c);
371

372
			if (c > 0) {
373 374
				free(current->new_version);
				current->new_version = version;
375
			} else
376 377 378 379
				free(version);

			return RET_NOTHING;
		}
380 381 382
		if (versioncmp > 0 && verbose > 30)
			fprintf(stderr,
"'%s' from '%s' is newer than '%s' currently\n",
383
				version, package->name, current->version);
384
		decision = predecide(predecide_data, upgrade->target,
385
				package, current->version);
386 387 388 389
		if (decision != UD_UPGRADE) {
			if (decision == UD_LOUDNO)
				fprintf(stderr,
"Loudly rejecting '%s' '%s' to enter '%s'!\n",
390
						package->name, version,
391
						upgrade->target->identifier);
392 393 394
			/* Even if we do not install it, setting it on hold
			 * will keep it or even install from a mirror before
			 * the delete was applied */
395
			if (decision == UD_HOLD)
396
				current->deleted = false;
397
			free(version);
398 399 400 401 402
			/* while supersede will remove the current package */
			if (decision == UD_SUPERSEDE) {
				current->deleted = true;
				return RET_OK;
			}
403
			return (decision==UD_ERROR)?RET_ERROR:RET_NOTHING;
404 405
		}

406
		if (versioncmp == 0) {
407 408
		/* we are replacing a package with the same version,
		 * so we keep the old one for sake of speed. */
409
			if (current->deleted &&
410 411 412 413 414 415
				current->version != current->new_version) {
				/* remember the version for checkupdate/pull */
				free(current->new_version);
				current->new_version = version;
			} else
					free(version);
416
			current->deleted = false;
417 418
			return RET_NOTHING;
		}
419 420
		if (versioncmp != 0 && current->version == current->new_version
				&& current->version_in_use != NULL) {
421 422
			/* The version to include is not the newest after the
			 * last deletion round), but maybe older, maybe newer.
423
			 * So we get to the question: it is also not the same
424
			 * like the version we already have? */
425
			int vcmp = 1;
426 427 428
			(void)dpkgversions_cmp(version,
					current->version_in_use, &vcmp);
			if (vcmp == 0) {
429
				current->version = current->version_in_use;
430
				if (current->deleted) {
431
					free(current->new_version);
432
					current->new_version = version;
433
				} else
434
					free(version);
435
				current->deleted = false;
436 437 438 439 440 441
				return RET_NOTHING;
			}
		}

// TODO: the following case might be worth considering, but sadly new_version
// might have changed without the proper data set.
442
//		if (versioncmp >= 0 && current->version == current->version_in_use
443
//				&& current->new_version != NULL) 
444

445
		current->architecture = package->architecture;
446
		r = upgrade->target->getinstalldata(upgrade->target,
447
				package,
448
				&control, &files, &origfiles);
449
		if (RET_WAS_ERROR(r)) {
450 451 452
			free(version);
			return r;
		}
453 454
		/* apply override data */
		r = upgrade->target->doreoverride(upgrade->target,
455
				package->name, control, &newcontrol);
456
		if (RET_WAS_ERROR(r)) {
457 458 459 460 461 462
			free(version);
			free(control);
			strlist_done(&files);
			checksumsarray_done(&origfiles);
			return r;
		}
463
		if (RET_IS_OK(r)) {
464 465 466
			free(control);
			control = newcontrol;
		}
467
		current->deleted = false;
468 469 470
		free(current->new_version);
		current->new_version = version;
		current->version = version;
471
		current->privdata = privdata;
472
		strlist_move(&current->new_filekeys, &files);
473
		checksumsarray_move(&current->new_origfiles, &origfiles);
474 475 476 477 478 479
		free(current->new_control);
		current->new_control = control;
	}
	return RET_OK;
}

480
retvalue upgradelist_update(struct upgradelist *upgrade, void *privdata, const char *filename, upgrade_decide_function *decide, void *decide_data, bool ignorewrongarchitecture) {
481
	struct indexfile *i;
482
	struct package package;
483
	retvalue result, r;
484

485
	r = indexfile_open(&i, filename, c_none);
486
	if (!RET_IS_OK(r))
487
		return r;
488

489
	result = RET_NOTHING;
490
	upgrade->last = NULL;
491 492
	setzero(struct package, &package);
	while (indexfile_getnext(i, &package,
493
				upgrade->target, ignorewrongarchitecture)) {
494
		r = package_getsource(&package);
Bernhard Link's avatar
Bernhard Link committed
495 496
		if (RET_IS_OK(r)) {
			r = upgradelist_trypackage(upgrade, privdata,
497
					decide, decide_data, &package);
Bernhard Link's avatar
Bernhard Link committed
498 499
			RET_UPDATE(result, r);
		}
500
		package_done(&package);
501 502
		if (RET_WAS_ERROR(r)) {
			if (verbose > 0)
503 504 505 506
				fprintf(stderr,
"Stop reading further chunks from '%s' due to previous errors.\n", filename);
			break;
		}
507
		if (interrupted()) {
508
			result = RET_ERROR_INTERRUPTED;
509 510
			break;
		}
511 512 513 514
	}
	r = indexfile_close(i);
	RET_ENDUPDATE(result, r);
	return result;
515
}
516

517
retvalue upgradelist_pull(struct upgradelist *upgrade, struct target *source, upgrade_decide_function *predecide, void *decide_data, void *privdata) {
518
	retvalue result, r;
519
	struct package_cursor iterator;
520 521

	upgrade->last = NULL;
522
	r = package_openiterator(source, READONLY, &iterator);
523
	if (RET_WAS_ERROR(r))
524
		return r;
525
	result = RET_NOTHING;
526
	while (package_next(&iterator)) {
527
		assert (source->packagetype == upgrade->target->packagetype);
528

529
		r = package_getversion(&iterator.current);
530 531
		assert (r != RET_NOTHING);
		if (!RET_IS_OK(r)) {
532 533 534
			RET_UPDATE(result, r);
			break;
		}
535
		r = package_getarchitecture(&iterator.current);
536
		if (!RET_IS_OK(r)) {
537 538 539
			RET_UPDATE(result, r);
			break;
		}
540 541 542
		if (iterator.current.architecture != architecture_all &&
				iterator.current.architecture !=
					upgrade->target->architecture) {
543 544
			continue;
		}
Bernhard Link's avatar
Bernhard Link committed
545

546
		r = package_getsource(&iterator.current);
Bernhard Link's avatar
Bernhard Link committed
547 548 549
		if (RET_IS_OK(r)) {
			r = upgradelist_trypackage(upgrade, privdata,
					predecide, decide_data,
550
					&iterator.current);
Bernhard Link's avatar
Bernhard Link committed
551 552
			RET_UPDATE(result, r);
		}
553
		if (RET_WAS_ERROR(r))
554
			break;
555
		if (interrupted()) {
556
			result = RET_ERROR_INTERRUPTED;
557 558
			break;
		}
559
	}
560
	r = package_closeiterator(&iterator);
561
	RET_ENDUPDATE(result, r);
562 563 564
	return result;
}

565 566 567 568
/* mark all packages as deleted, so they will vanis unless readded or reholded */
retvalue upgradelist_deleteall(struct upgradelist *upgrade) {
	struct package_data *pkg;

569
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
570
		pkg->deleted = true;
571 572 573 574 575
	}

	return RET_OK;
}

576
/* request all wanted files in the downloadlists given before */
577
retvalue upgradelist_enqueue(struct upgradelist *upgrade, enqueueaction *action, void *calldata) {
578
	struct package_data *pkg;
579
	retvalue result, r;
580
	result = RET_NOTHING;
581
	assert(upgrade != NULL);
582 583
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version == pkg->new_version && !pkg->deleted) {
584
			r = action(calldata, &pkg->new_origfiles,
585
					&pkg->new_filekeys, pkg->privdata);
586 587
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
588 589 590 591 592 593
				break;
		}
	}
	return result;
}

594
/* delete all packages that will not be kept (i.e. either deleted or upgraded) */
595
retvalue upgradelist_predelete(struct upgradelist *upgrade, struct logger *logger) {
596
	struct package_data *pkg;
597
	retvalue result, r;
598 599
	result = RET_NOTHING;
	assert(upgrade != NULL);
600

601
	result = target_initpackagesdb(upgrade->target, READWRITE);
602
	if (RET_WAS_ERROR(result))
603
		return result;
604 605 606 607 608
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version_in_use != NULL &&
				(pkg->version == pkg->new_version
				 || pkg->deleted)) {
			if (interrupted())
609
				r = RET_ERROR_INTERRUPTED;
Bernhard Link's avatar
Bernhard Link committed
610
			else
Bernhard Link's avatar
Bernhard Link committed
611
				r = target_removepackage(upgrade->target,
612
						logger, pkg->name, NULL);
613 614
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
615 616 617
				break;
		}
	}
618
	r = target_closepackagesdb(upgrade->target);
619
	RET_ENDUPDATE(result, r);
620 621 622
	return result;
}

Bernhard Link's avatar
Bernhard Link committed
623 624 625 626
bool upgradelist_isbigdelete(const struct upgradelist *upgrade) {
	struct package_data *pkg;
	long long deleted = 0, all = 0;

627
	if (upgrade->list == NULL)
Bernhard Link's avatar
Bernhard Link committed
628
		return false;
629 630
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version_in_use == NULL)
Bernhard Link's avatar
Bernhard Link committed
631 632
		       continue;
		all++;
633
		if (pkg->deleted)
Bernhard Link's avatar
Bernhard Link committed
634 635 636 637 638
			deleted++;
	}
	return deleted >= 10 && all/deleted < 5;
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652
bool upgradelist_woulddelete(const struct upgradelist *upgrade) {
	struct package_data *pkg;

	if (upgrade->list == NULL)
		return false;
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version_in_use == NULL)
		       continue;
		if (pkg->deleted)
			return true;
	}
	return false;
}

653
retvalue upgradelist_install(struct upgradelist *upgrade, struct logger *logger, bool ignoredelete, void (*callback)(void *, const char **, const char **)){
654
	struct package_data *pkg;
655
	retvalue result, r;
656

657
	if (upgrade->list == NULL)
658 659
		return RET_NOTHING;

660
	result = target_initpackagesdb(upgrade->target, READWRITE);
661
	if (RET_WAS_ERROR(result))
662
		return result;
663
	result = RET_NOTHING;
664 665
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version == pkg->new_version && !pkg->deleted) {
666 667
			char *newcontrol;

668 669
			assert ((pkg->architecture == architecture_all &&
				 upgrade->target->packagetype != pt_dsc)
670
				|| pkg->architecture ==
671
					upgrade->target->architecture);
672

673
			r = files_checkorimprove(&pkg->new_filekeys,
674
					pkg->new_origfiles.checksums);
675
			if (! RET_WAS_ERROR(r)) {
676 677 678 679 680 681

				r = upgrade->target->completechecksums(
						pkg->new_control,
						&pkg->new_filekeys,
						pkg->new_origfiles.checksums,
						&newcontrol);
682
				assert (r != RET_NOTHING);
683
			}
684
			if (! RET_WAS_ERROR(r)) {
Bernhard Link's avatar
Bernhard Link committed
685
				/* upgrade (or possibly downgrade) */
686 687 688
				const char *causingrule = NULL,
				      *suitefrom = NULL;

689 690
				free(pkg->new_control);
				pkg->new_control = newcontrol;
691
				newcontrol = NULL;
692 693
				callback(pkg->privdata,
						&causingrule, &suitefrom);
694
// TODO: trackingdata?
695
				if (interrupted())
696
					r = RET_ERROR_INTERRUPTED;
697 698
				else
					r = target_addpackage(upgrade->target,
699
						logger, pkg->name,
700 701
						pkg->new_version,
						pkg->new_control,
702
						&pkg->new_filekeys, true,
703
						NULL, pkg->architecture,
704
						causingrule, suitefrom);
705
			}
706 707
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
708 709
				break;
		}
710 711 712
		if (pkg->deleted && pkg->version_in_use != NULL
				&& !ignoredelete) {
			if (interrupted())
713
				r = RET_ERROR_INTERRUPTED;
714
			else
Bernhard Link's avatar
Bernhard Link committed
715
				r = target_removepackage(upgrade->target,
716
						logger, pkg->name, NULL);
717 718
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
719 720
				break;
		}
721
	}
722
	r = target_closepackagesdb(upgrade->target);
723
	RET_ENDUPDATE(result, r);
724 725 726
	return result;
}

727
void upgradelist_dump(struct upgradelist *upgrade, dumpaction action){
728
	struct package_data *pkg;
729

730
	assert(upgrade != NULL);
731

732 733
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (interrupted())
734
			return;
735
		if (pkg->deleted)
736 737 738
			action(pkg->name, pkg->version_in_use,
					NULL, pkg->new_version,
					NULL, NULL, pkg->privdata);
739
		else if (pkg->version == pkg->version_in_use)
740 741 742 743 744 745 746 747
			action(pkg->name, pkg->version_in_use,
					pkg->version_in_use, pkg->new_version,
					NULL, NULL, pkg->privdata);
		else
			action(pkg->name, pkg->version_in_use,
					pkg->new_version, NULL,
					&pkg->new_filekeys, pkg->new_control,
					pkg->privdata);
748 749
	}
}