upgradelist.c 20.2 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 64
	/* cache/info what description is needed for this */
	struct description *description;
65
	struct checksumsarray new_origfiles;
66 67
	/* to destinguish arch all from not arch all */
	architecture_t architecture;
68
};
69

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

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

Bernhard Link's avatar
Bernhard Link committed
92 93 94
/* 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,
95
 * upgrade->last to the last one inserted */
96
static retvalue save_package_version(struct upgradelist *upgrade, struct package *pkg) {
97
	retvalue r;
98
	struct package_data *package;
99

100
	r = package_getversion(pkg);
101
	if (RET_WAS_ERROR(r))
102 103
		return r;

104
	package = zNEW(struct package_data);
105
	if (FAILEDTOALLOC(package))
106 107
		return RET_ERROR_OOM;

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

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

	return RET_OK;
}
142

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

148 149
	upgrade = zNEW(struct upgradelist);
	if (FAILEDTOALLOC(upgrade))
150 151
		return RET_ERROR_OOM;

152
	upgrade->target = t;
153

154
	/* Beginn with the packages currently in the archive */
155

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

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

	upgrade->last = NULL;

	*ul = upgrade;
	return RET_OK;
}

181
void upgradelist_free(struct upgradelist *upgrade) {
182
	struct package_data *l;
183

184
	if (upgrade == NULL)
185
		return;
186 187

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

194
	free(upgrade);
195
	return;
196 197
}

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

204 205

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

214 215 216 217
	version = package_dupversion(package);
	if (FAILEDTOALLOC(version))
		return RET_ERROR_OOM;

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

226 227 228
	/* 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
229
	 * again and again... and again... and even some more...*/
230

231
	while (true) {
232
		int cmp;
233

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

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

242
		if (cmp == 0)
243 244
			break;

245
		if (cmp < 0) {
246 247
			int precmp;

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

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

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

356
		upgrade->last = current;
357

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

370
			if (current->new_version == current->version)
371
				c =versioncmp;
372
			else if (current->new_version == NULL)
373 374
				c = 1;
			else (void)dpkgversions_cmp(version,
375
					       current->new_version, &c);
376

377
			if (c > 0) {
378 379
				free(current->new_version);
				current->new_version = version;
380
			} else
381 382 383 384
				free(version);

			return RET_NOTHING;
		}
385 386 387
		if (versioncmp > 0 && verbose > 30)
			fprintf(stderr,
"'%s' from '%s' is newer than '%s' currently\n",
388
				version, package->name, current->version);
389
		decision = predecide(predecide_data, upgrade->target,
390
				current->name, package->source,
Bernhard Link's avatar
Bernhard Link committed
391
				current->version,
392 393
				version, package->sourceversion,
				package->control);
394 395 396 397
		if (decision != UD_UPGRADE) {
			if (decision == UD_LOUDNO)
				fprintf(stderr,
"Loudly rejecting '%s' '%s' to enter '%s'!\n",
398
						package->name, version,
399
						upgrade->target->identifier);
400 401 402
			/* 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 */
403
			if (decision == UD_HOLD)
404
				current->deleted = false;
405
			free(version);
406 407 408 409 410
			/* while supersede will remove the current package */
			if (decision == UD_SUPERSEDE) {
				current->deleted = true;
				return RET_OK;
			}
411
			return (decision==UD_ERROR)?RET_ERROR:RET_NOTHING;
412 413
		}

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

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

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

489
retvalue upgradelist_update(struct upgradelist *upgrade, void *privdata, const char *filename, upgrade_decide_function *decide, void *decide_data, bool ignorewrongarchitecture) {
490
	struct indexfile *i;
491
	struct package package;
492
	retvalue result, r;
493

494
	r = indexfile_open(&i, filename, c_none);
495
	if (!RET_IS_OK(r))
496
		return r;
497

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

526
retvalue upgradelist_pull(struct upgradelist *upgrade, struct target *source, upgrade_decide_function *predecide, void *decide_data, void *privdata) {
527
	retvalue result, r;
528
	struct package_cursor iterator;
529 530

	upgrade->last = NULL;
531
	r = package_openiterator(source, READONLY, &iterator);
532
	if (RET_WAS_ERROR(r))
533
		return r;
534
	result = RET_NOTHING;
535
	while (package_next(&iterator)) {
536
		assert (source->packagetype == upgrade->target->packagetype);
537

538
		r = package_getversion(&iterator.current);
539 540
		assert (r != RET_NOTHING);
		if (!RET_IS_OK(r)) {
541 542 543
			RET_UPDATE(result, r);
			break;
		}
544
		r = package_getarchitecture(&iterator.current);
545
		if (!RET_IS_OK(r)) {
546 547 548
			RET_UPDATE(result, r);
			break;
		}
549 550 551
		if (iterator.current.architecture != architecture_all &&
				iterator.current.architecture !=
					upgrade->target->architecture) {
552 553
			continue;
		}
Bernhard Link's avatar
Bernhard Link committed
554

555
		r = package_getsource(&iterator.current);
Bernhard Link's avatar
Bernhard Link committed
556 557 558
		if (RET_IS_OK(r)) {
			r = upgradelist_trypackage(upgrade, privdata,
					predecide, decide_data,
559
					&iterator.current);
Bernhard Link's avatar
Bernhard Link committed
560 561
			RET_UPDATE(result, r);
		}
562
		if (RET_WAS_ERROR(r))
563
			break;
564
		if (interrupted()) {
565
			result = RET_ERROR_INTERRUPTED;
566 567
			break;
		}
568
	}
569
	r = package_closeiterator(&iterator);
570
	RET_ENDUPDATE(result, r);
571 572 573
	return result;
}

574 575 576 577
/* mark all packages as deleted, so they will vanis unless readded or reholded */
retvalue upgradelist_deleteall(struct upgradelist *upgrade) {
	struct package_data *pkg;

578
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
579
		pkg->deleted = true;
580 581 582 583 584
	}

	return RET_OK;
}

585
/* request all wanted files in the downloadlists given before */
586
retvalue upgradelist_enqueue(struct upgradelist *upgrade, enqueueaction *action, void *calldata) {
587
	struct package_data *pkg;
588
	retvalue result, r;
589
	result = RET_NOTHING;
590
	assert(upgrade != NULL);
591 592
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version == pkg->new_version && !pkg->deleted) {
593
			r = action(calldata, &pkg->new_origfiles,
594
					&pkg->new_filekeys, pkg->privdata);
595 596
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
597 598 599 600 601 602
				break;
		}
	}
	return result;
}

603
/* delete all packages that will not be kept (i.e. either deleted or upgraded) */
604
retvalue upgradelist_predelete(struct upgradelist *upgrade, struct logger *logger) {
605
	struct package_data *pkg;
606
	retvalue result, r;
607 608
	result = RET_NOTHING;
	assert(upgrade != NULL);
609

610
	result = target_initpackagesdb(upgrade->target, READWRITE);
611
	if (RET_WAS_ERROR(result))
612
		return result;
613 614 615 616 617
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version_in_use != NULL &&
				(pkg->version == pkg->new_version
				 || pkg->deleted)) {
			if (interrupted())
618
				r = RET_ERROR_INTERRUPTED;
Bernhard Link's avatar
Bernhard Link committed
619
			else
Bernhard Link's avatar
Bernhard Link committed
620
				r = target_removepackage(upgrade->target,
621
						logger, pkg->name, NULL);
622 623
			RET_UPDATE(result, r);
			if (RET_WAS_ERROR(r))
624 625 626
				break;
		}
	}
627
	r = target_closepackagesdb(upgrade->target);
628
	RET_ENDUPDATE(result, r);
629 630 631
	return result;
}

Bernhard Link's avatar
Bernhard Link committed
632 633 634 635
bool upgradelist_isbigdelete(const struct upgradelist *upgrade) {
	struct package_data *pkg;
	long long deleted = 0, all = 0;

636
	if (upgrade->list == NULL)
Bernhard Link's avatar
Bernhard Link committed
637
		return false;
638 639
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version_in_use == NULL)
Bernhard Link's avatar
Bernhard Link committed
640 641
		       continue;
		all++;
642
		if (pkg->deleted)
Bernhard Link's avatar
Bernhard Link committed
643 644 645 646 647
			deleted++;
	}
	return deleted >= 10 && all/deleted < 5;
}

648 649 650 651 652 653 654 655 656 657 658 659 660 661
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;
}

662
retvalue upgradelist_install(struct upgradelist *upgrade, struct logger *logger, bool ignoredelete, void (*callback)(void *, const char **, const char **)){
663
	struct package_data *pkg;
664
	retvalue result, r;
665

666
	if (upgrade->list == NULL)
667 668
		return RET_NOTHING;

669
	result = target_initpackagesdb(upgrade->target, READWRITE);
670
	if (RET_WAS_ERROR(result))
671
		return result;
672
	result = RET_NOTHING;
673 674
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (pkg->version == pkg->new_version && !pkg->deleted) {
675 676
			char *newcontrol;

677 678
			assert ((pkg->architecture == architecture_all &&
				 upgrade->target->packagetype != pt_dsc)
679
				|| pkg->architecture ==
680
					upgrade->target->architecture);
681

682
			r = files_checkorimprove(&pkg->new_filekeys,
683
					pkg->new_origfiles.checksums);
684
			if (! RET_WAS_ERROR(r)) {
685 686 687 688 689 690

				r = upgrade->target->completechecksums(
						pkg->new_control,
						&pkg->new_filekeys,
						pkg->new_origfiles.checksums,
						&newcontrol);
691
				assert (r != RET_NOTHING);
692
			}
693
			if (! RET_WAS_ERROR(r)) {
Bernhard Link's avatar
Bernhard Link committed
694
				/* upgrade (or possibly downgrade) */
695 696 697
				const char *causingrule = NULL,
				      *suitefrom = NULL;

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

737
void upgradelist_dump(struct upgradelist *upgrade, dumpaction action){
738
	struct package_data *pkg;
739

740
	assert(upgrade != NULL);
741

742 743
	for (pkg = upgrade->list ; pkg != NULL ; pkg = pkg->next) {
		if (interrupted())
744
			return;
745
		if (pkg->deleted)
746 747 748
			action(pkg->name, pkg->version_in_use,
					NULL, pkg->new_version,
					NULL, NULL, pkg->privdata);
749
		else if (pkg->version == pkg->version_in_use)
750 751 752 753 754 755 756 757
			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);
758 759
	}
}