static retvalue addpackages(struct target *target, const char *packagename, const char *controlchunk, /*@null@*/const char *oldcontrolchunk, const char *version, /*@null@*/const char *oldversion, const struct strlist *files, /*@only@*//*@null@*/struct strlist *oldfiles, /*@null@*/struct logger *logger, /*@null@*/struct trackingdata *trackingdata, architecture_t architecture, /*@null@*/const char *oldsource, /*@null@*/const char *oldsversion, /*@null@*/const char *causingrule, /*@null@*/const char *suitefrom) { retvalue result, r; struct table *table = target->packages; enum filetype filetype; assert (atom_defined(architecture)); if (architecture == architecture_source) filetype = ft_SOURCE; else if (architecture == architecture_all) filetype = ft_ALL_BINARY; else filetype = ft_ARCH_BINARY; /* mark it as needed by this distribution */ r = references_insert(target->identifier, files, oldfiles); if (RET_WAS_ERROR(r)) { if (oldfiles != NULL) strlist_done(oldfiles); return r; } /* Add package to the distribution's database */ if (oldcontrolchunk != NULL) { result = table_replacerecord(table, packagename, controlchunk); } else { result = table_adduniqrecord(table, packagename, controlchunk); } if (RET_WAS_ERROR(result)) { if (oldfiles != NULL) strlist_done(oldfiles); return result; } if (logger != NULL) logger_log(logger, target, packagename, version, oldversion, controlchunk, oldcontrolchunk, files, oldfiles, causingrule, suitefrom); r = trackingdata_insert(trackingdata, filetype, files, oldsource, oldsversion, oldfiles); RET_UPDATE(result, r); /* remove old references to files */ if (oldfiles != NULL) { r = references_delete(target->identifier, oldfiles, files); RET_UPDATE(result, r); strlist_done(oldfiles); } return result; }
retvalue tracking_tidyall(trackingdb t) { struct cursor *cursor; retvalue result, r; struct trackedpackage *pkg; const char *key, *value, *data; size_t datalen; r = table_newglobalcursor(t->table, &cursor); if (!RET_IS_OK(r)) return r; result = RET_NOTHING; while (cursor_nextpair(t->table, cursor, &key, &value, &data, &datalen)) { r = parse_data(key, value, data, datalen, &pkg); if (RET_WAS_ERROR(r)) { result = r; break; } r = trackedpackage_tidy(t, pkg); RET_UPDATE(result, r); r = tracking_saveatcursor(t, cursor, pkg); RET_UPDATE(result, r); trackedpackage_free(pkg); } r = cursor_close(t->table, cursor); RET_UPDATE(result, r); return result; }
retvalue trackingdata_remove(struct trackingdata *data, /*@only@*/char*oldsource, /*@only@*/char*oldversion, const struct strlist *oldfilekeys) { retvalue result, r; struct trackedpackage *pkg; assert(oldsource != NULL && oldversion != NULL && oldfilekeys != NULL); if (data->pkg != NULL && strcmp(oldversion, data->pkg->sourceversion) == 0 && strcmp(oldsource, data->pkg->sourcename) == 0) { /* Unlikely, but it may also be the same source version as * the package we are currently adding */ free(oldsource); free(oldversion); return trackedpackage_removefilekeys(data->tracks, data->pkg, oldfilekeys); } result = tracking_get(data->tracks, oldsource, oldversion, &pkg); if (RET_WAS_ERROR(result)) { free(oldsource); free(oldversion); return result; } if (result == RET_NOTHING) { fprintf(stderr, "Could not found tracking data for %s_%s in %s to remove old files from it.\n", oldsource, oldversion, data->tracks->codename); free(oldsource); free(oldversion); return RET_OK; } r = trackedpackage_removefilekeys(data->tracks, pkg, oldfilekeys); RET_UPDATE(result, r); r = tracking_save(data->tracks, pkg); RET_UPDATE(result, r); r = trackingdata_remember(data, oldsource, oldversion); RET_UPDATE(result, r); return result; }
retvalue aptmethod_download(struct aptmethodrun *run) { struct aptmethod *method; retvalue result, r; int workleft; result = RET_NOTHING; /* fire up all methods, removing those that do not work: */ for (method = run->methods; method != NULL ; method = method->next) { r = aptmethod_startup(method); /* do not remove failed methods here any longer, * and not remove methods having nothing to do, * as this breaks when no index files are downloaded * due to all already being in place... */ RET_UPDATE(result, r); } /* waiting for them to finish: */ do { r = checkchilds(run); RET_UPDATE(result, r); r = readwrite(run, &workleft); RET_UPDATE(result, r); // TODO: check interrupted here... } while (workleft > 0 || uncompress_running()); return result; }
retvalue pull_update(struct pull_distribution *distributions) { retvalue result, r; struct pull_distribution *d; for (d=distributions ; d != NULL ; d=d->next) { r = distribution_prepareforwriting(d->distribution); if (RET_WAS_ERROR(r)) return r; r = distribution_loadalloverrides(d->distribution); if (RET_WAS_ERROR(r)) return r; } if (verbose >= 0) printf("Calculating packages to pull...\n"); result = RET_NOTHING; for (d=distributions ; d != NULL ; d=d->next) { r = pull_search(stdout, d); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) break; // TODO: make already here sure the files are ready? } if (RET_WAS_ERROR(result)) { for (d=distributions ; d != NULL ; d=d->next) { struct pull_target *u; for (u=d->targets ; u != NULL ; u=u->next) { upgradelist_free(u->upgradelist); u->upgradelist = NULL; } } return result; } if (verbose >= 0) printf("Installing (and possibly deleting) packages...\n"); for (d=distributions ; d != NULL ; d=d->next) { if (global.onlysmalldeletes) { if (pull_isbigdelete(d)) { fprintf(stderr, "Not processing '%s' because of --onlysmalldeletes\n", d->distribution->codename); continue; } } r = pull_install(d); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) break; } logger_wait(); return result; }
retvalue files_collectnewchecksums(void) { retvalue result, r; struct cursor *cursor; const char *filekey, *all; size_t alllen; struct checksums *expected; char *fullfilename; result = RET_NOTHING; r = table_newglobalcursor(rdb_checksums, &cursor); if (!RET_IS_OK(r)) return r; while (cursor_nexttempdata(rdb_checksums, cursor, &filekey, &all, &alllen)) { r = checksums_setall(&expected, all, alllen); if (!RET_IS_OK(r)) { RET_UPDATE(result, r); continue; } if (checksums_iscomplete(expected)) { checksums_free(expected); continue; } fullfilename = files_calcfullfilename(filekey); if (FAILEDTOALLOC(fullfilename)) { result = RET_ERROR_OOM; checksums_free(expected); break; } r = checksums_complete(&expected, fullfilename); if (r == RET_NOTHING) { fprintf(stderr, "Missing file '%s'!\n", fullfilename); r = RET_ERROR_MISSING; } if (r == RET_ERROR_WRONG_MD5) { fprintf(stderr, "ERROR: Cannot collect missing checksums for '%s'\n" "as the file in the pool does not match the already recorded checksums\n", filekey); } free(fullfilename); if (RET_IS_OK(r)) r = files_replace_checksums(filekey, expected); checksums_free(expected); RET_UPDATE(result, r); } r = cursor_close(rdb_checksums, cursor); RET_ENDUPDATE(result, r); return result; }
/* remove all references from a given identifier */ retvalue references_remove(const char *neededby) { struct cursor *cursor; retvalue result, r; const char *found_to, *found_by; size_t datalen, l; r = table_newglobalcursor(rdb_references, &cursor); if (!RET_IS_OK(r)) return r; l = strlen(neededby); result = RET_NOTHING; while (cursor_nexttempdata(rdb_references, cursor, &found_to, &found_by, &datalen)) { if (datalen >= l && strncmp(found_by, neededby, l) == 0 && (found_by[l] == '\0' || found_by[l] == ' ')) { if (verbose > 8) fprintf(stderr, "Removing reference to '%s' by '%s'\n", found_to, neededby); r = cursor_delete(rdb_references, cursor, found_to, NULL); RET_UPDATE(result, r); if (RET_IS_OK(r)) { r = pool_dereferenced(found_to); RET_ENDUPDATE(result, r); } } } r = cursor_close(rdb_references, cursor); RET_ENDUPDATE(result, r); return result; }
retvalue pull_checkupdate(struct pull_distribution *distributions) { struct pull_distribution *d; retvalue result, r; for (d=distributions ; d != NULL ; d=d->next) { r = distribution_loadalloverrides(d->distribution); if (RET_WAS_ERROR(r)) return r; } if (verbose >= 0) fprintf(stderr, "Calculating packages to get...\n"); result = RET_NOTHING; for (d=distributions ; d != NULL ; d=d->next) { r = pull_search(stderr, d); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) break; pull_dump(d); } return result; }
retvalue tracking_printall(trackingdb t) { struct cursor *cursor; retvalue result, r; struct trackedpackage *pkg; const char *key, *value, *data; size_t datalen; r = table_newglobalcursor(t->table, &cursor); if (!RET_IS_OK(r)) return r; result = RET_NOTHING; while (cursor_nextpair(t->table, cursor, &key, &value, &data, &datalen)) { r = parse_data(key, value, data, datalen, &pkg); if (RET_IS_OK(r)) { print(t->codename, pkg); trackedpackage_free(pkg); } RET_UPDATE(result, r); } r = cursor_close(t->table, cursor); RET_ENDUPDATE(result, r); return result; }
retvalue files_checkpool(bool fast) { retvalue result, r; struct cursor *cursor; const char *filekey, *combined; size_t combinedlen; struct checksums *expected; char *fullfilename; bool improveable = false; result = RET_NOTHING; r = table_newglobalcursor(rdb_checksums, &cursor); if (!RET_IS_OK(r)) return r; while (cursor_nexttempdata(rdb_checksums, cursor, &filekey, &combined, &combinedlen)) { r = checksums_setall(&expected, combined, combinedlen); if (RET_WAS_ERROR(r)) { RET_UPDATE(result, r); continue; } fullfilename = files_calcfullfilename(filekey); if (FAILEDTOALLOC(fullfilename)) { result = RET_ERROR_OOM; checksums_free(expected); break; } if (fast) r = checksums_cheaptest(fullfilename, expected, true); else r = checkpoolfile(fullfilename, expected, &improveable); if (r == RET_NOTHING) { fprintf(stderr, "Missing file '%s'!\n", fullfilename); r = RET_ERROR_MISSING; } free(fullfilename); checksums_free(expected); RET_UPDATE(result, r); } r = cursor_close(rdb_checksums, cursor); RET_ENDUPDATE(result, r); if (improveable && verbose >= 0) printf( "There were files with only some of the checksums this version of reprepro\n" "can compute recorded. To add those run reprepro collectnewchecksums.\n"); return result; }
retvalue tracking_rereference(struct distribution *distribution) { retvalue result, r; trackingdb tracks; result = references_remove(distribution->codename); if (distribution->tracking == dt_NONE) return result; r = tracking_initialize(&tracks, distribution, true); RET_UPDATE(result, r); if (!RET_IS_OK(r)) return result; r = tracking_recreatereferences(tracks); RET_UPDATE(result, r); r = tracking_done(tracks); RET_ENDUPDATE(result, r); return result; }
/* Like target_removepackage, but delete the package record by cursor */ retvalue package_remove_by_cursor(struct package_cursor *tc, struct logger *logger, struct trackingdata *trackingdata) { struct target * const target = tc->target; struct package *old = &tc->current; struct strlist files; retvalue result, r; assert (target != NULL && target->packages != NULL); assert (target == old->target); if (logger != NULL) { (void)package_getversion(old); } r = old->target->getfilekeys(old->control, &files); if (RET_WAS_ERROR(r)) { return r; } if (trackingdata != NULL) { (void)package_getsource(old); } if (verbose > 0) printf("removing '%s' from '%s'...\n", old->name, old->target->identifier); result = cursor_delete(target->packages, tc->cursor, old->name, NULL); if (RET_IS_OK(result)) { old->target->wasmodified = true; if (trackingdata != NULL && old->source != NULL && old->sourceversion != NULL) { r = trackingdata_remove(trackingdata, old->source, old->sourceversion, &files); RET_UPDATE(result, r); } if (trackingdata == NULL) old->target->staletracking = true; if (logger != NULL) logger_log(logger, old->target, old->name, NULL, old->version, NULL, old->control, NULL, &files, NULL, NULL); r = references_delete(old->target->identifier, &files, NULL); RET_UPDATE(result, r); } strlist_done(&files); return result; }
retvalue tracking_drop(const char *codename) { retvalue result, r; result = database_dropsubtable("tracking.db", codename); r = references_remove(codename); RET_UPDATE(result, r); return result; }
retvalue tracking_remove(trackingdb t, const char *sourcename, const char *version) { retvalue result, r; struct cursor *cursor; const char *data; size_t datalen; char *id; struct trackedpackage *pkg SETBUTNOTUSED(= NULL); r = table_newpairedcursor(t->table, sourcename, version, &cursor, &data, &datalen); if (!RET_IS_OK(r)) return r; id = calc_trackreferee(t->codename, sourcename, version); if (FAILEDTOALLOC(id)) { (void)cursor_close(t->table, cursor); return RET_ERROR_OOM; } result = parse_data(sourcename, version, data, datalen, &pkg); if (RET_IS_OK(r)) { assert (pkg != NULL); r = references_delete(id, &pkg->filekeys, NULL); RET_UPDATE(result, r); trackedpackage_free(pkg); } else { RET_UPDATE(result, r); fprintf(stderr, "Could not parse data, removing all references blindly...\n"); r = references_remove(id); RET_UPDATE(result, r); } free(id); r = cursor_delete(t->table, cursor, sourcename, version); if (RET_IS_OK(r)) fprintf(stderr, "Removed %s_%s from %s.\n", sourcename, version, t->codename); RET_UPDATE(result, r); r = cursor_close(t->table, cursor); RET_ENDUPDATE(result, r); return result; }
/* create dirname and any '/'-separated part of it */ retvalue dirs_make_recursive(const char *directory) { retvalue r, result; if (interrupted()) { return RET_ERROR_INTERRUPTED; } r = dirs_make_parent(directory); result = dirs_create(directory); RET_UPDATE(result, r); return result; }
static retvalue tracking_foreachversion(trackingdb t, struct distribution *distribution, const char *sourcename, retvalue (action)(trackingdb t, struct trackedpackage *, struct distribution *)) { struct cursor *cursor; retvalue result, r; struct trackedpackage *pkg; const char *value, *data; size_t datalen; r = table_newduplicatecursor(t->table, sourcename, &cursor, &value, &data, &datalen); if (!RET_IS_OK(r)) return r; result = RET_NOTHING; do { r = parse_data(sourcename, value, data, datalen, &pkg); if (RET_WAS_ERROR(r)) { result = r; break; } if (verbose > 10) printf("Processing track of '%s' version '%s'\n", pkg->sourcename, pkg->sourceversion); r = action(t, pkg, distribution); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) { (void)cursor_close(t->table, cursor); trackedpackage_free(pkg); return r; } r = trackedpackage_tidy(t, pkg); RET_ENDUPDATE(result, r); r = tracking_saveatcursor(t, cursor, pkg); RET_UPDATE(result, r); trackedpackage_free(pkg); } while (cursor_nextpair(t->table, cursor, NULL, &value, &data, &datalen)); r = cursor_close(t->table, cursor); RET_UPDATE(result, r); return result; }
static retvalue tracking_recreatereferences(trackingdb t) { struct cursor *cursor; retvalue result, r; struct trackedpackage *pkg; char *id; int i; const char *key, *value, *data; size_t datalen; r = table_newglobalcursor(t->table, &cursor); if (!RET_IS_OK(r)) return r; result = RET_NOTHING; while (cursor_nextpair(t->table, cursor, &key, &value, &data, &datalen)) { r = parse_data(key, value, data, datalen, &pkg); if (RET_WAS_ERROR(r)) { (void)cursor_close(t->table, cursor); return r; } id = calc_trackreferee(t->codename, pkg->sourcename, pkg->sourceversion); if (FAILEDTOALLOC(id)) { trackedpackage_free(pkg); (void)cursor_close(t->table, cursor); return RET_ERROR_OOM; } for (i = 0 ; i < pkg->filekeys.count ; i++) { const char *filekey = pkg->filekeys.values[i]; r = references_increment(filekey, id); RET_UPDATE(result, r); } free(id); trackedpackage_free(pkg); } r = cursor_close(t->table, cursor); RET_UPDATE(result, r); return result; }
/* callback for each registered file */ retvalue files_foreach(per_file_action action, void *privdata) { retvalue result, r; struct cursor *cursor; const char *filekey, *checksum; r = table_newglobalcursor(rdb_checksums, &cursor); if (!RET_IS_OK(r)) return r; result = RET_NOTHING; while (cursor_nexttemp(rdb_checksums, cursor, &filekey, &checksum)) { if (interrupted()) { RET_UPDATE(result, RET_ERROR_INTERRUPTED); break; } r = action(privdata, filekey); RET_UPDATE(result, r); } r = cursor_close(rdb_checksums, cursor); RET_ENDUPDATE(result, r); return result; }
/* Try to remove all packages causing refcounts in this tracking record */ static retvalue removesourcepackage(trackingdb t, struct trackedpackage *pkg, struct distribution *distribution) { struct target *target; retvalue result, r; int i; result = RET_NOTHING; for (target = distribution->targets ; target != NULL ; target = target->next) { r = target_initpackagesdb(target, READWRITE); RET_ENDUPDATE(result, r); if (RET_IS_OK(r)) { r = targetremovesourcepackage(t, pkg, distribution, target); RET_UPDATE(result, r); RET_UPDATE(distribution->status, r); r = target_closepackagesdb(target); RET_ENDUPDATE(result, r); RET_ENDUPDATE(distribution->status, r); if (RET_WAS_ERROR(result)) return result; } } for (i = 0 ; i < pkg->filekeys.count ; i++) { const char *filekey = pkg->filekeys.values[i]; if (pkg->refcounts[i] <= 0) continue; if (pkg->filetypes[i] != ft_ALL_BINARY && pkg->filetypes[i] != ft_SOURCE && pkg->filetypes[i] != ft_ARCH_BINARY) continue; fprintf(stderr, "There was an inconsistency in the tracking data of '%s':\n" "'%s' has refcount > 0, but was nowhere found.\n", distribution->codename, filekey); pkg->refcounts[i] = 0; } return result; }
static retvalue pull_search(/*@null@*/FILE *out, struct pull_distribution *d) { retvalue result, r; struct pull_target *u; result = RET_NOTHING; for (u=d->targets ; u != NULL ; u=u->next) { r = pull_searchformissing(out, u); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) break; } return result; }
retvalue trackedpackage_removefilekeys(trackingdb tracks, struct trackedpackage *pkg, const struct strlist *filekeys) { int i; retvalue result, r; assert (filekeys != NULL); result = RET_OK; for (i = 0 ; i < filekeys->count ; i++) { const char *filekey = filekeys->values[i]; r = trackedpackage_removefilekey(tracks, pkg, filekey); RET_UPDATE(result, r); } return result; }
static inline retvalue pull_searchformissing(/*@null@*/FILE *out, struct pull_target *p) { struct pull_source *source; retvalue result, r; if (verbose > 2 && out != NULL) fprintf(out, " pulling into '%s'\n", p->target->identifier); assert(p->upgradelist == NULL); r = upgradelist_initialize(&p->upgradelist, p->target); if (RET_WAS_ERROR(r)) return r; result = RET_NOTHING; for (source=p->sources ; source != NULL ; source=source->next) { if (source->rule == NULL) { if (verbose > 4 && out != NULL) fprintf(out, " marking everything to be deleted\n"); r = upgradelist_deleteall(p->upgradelist); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) return result; continue; } if (verbose > 4 && out != NULL) fprintf(out, " looking what to get from '%s'\n", source->source->identifier); r = upgradelist_pull(p->upgradelist, source->source, ud_decide_by_rule, source->rule, source); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) return result; } return result; }
retvalue trackedpackage_adddupfilekeys(trackingdb tracks, struct trackedpackage *pkg, enum filetype filetype, const struct strlist *filekeys, bool used) { int i; retvalue result, r; assert (filekeys != NULL); result = RET_OK; for (i = 0 ; i < filekeys->count ; i++) { char *filekey = strdup(filekeys->values[i]); r = trackedpackage_addfilekey(tracks, pkg, filetype, filekey, used); RET_UPDATE(result, r); } return result; }
static retvalue pull_install(struct pull_distribution *distribution) { retvalue result, r; struct pull_target *u; struct distribution *d = distribution->distribution; assert (logger_isprepared(d->logger)); result = RET_NOTHING; for (u=distribution->targets ; u != NULL ; u=u->next) { r = upgradelist_install(u->upgradelist, d->logger, false, pull_from_callback); RET_UPDATE(d->status, r); RET_UPDATE(result, r); upgradelist_free(u->upgradelist); u->upgradelist = NULL; if (RET_WAS_ERROR(r)) break; } if (RET_IS_OK(result) && d->tracking != dt_NONE) { r = tracking_retrack(d, false); RET_ENDUPDATE(result, r); } return result; }
/* Add an reference by <identifer> for the given <files>, * excluding <exclude>, if it is nonNULL. */ retvalue references_insert(const char *identifier, const struct strlist *files, const struct strlist *exclude) { retvalue result, r; int i; result = RET_NOTHING; for (i = 0 ; i < files->count ; i++) { const char *filename = files->values[i]; if (exclude == NULL || !strlist_in(exclude, filename)) { r = references_increment(filename, identifier); RET_UPDATE(result, r); } } return result; }
retvalue references_check(const char *referee, const struct strlist *filekeys) { int i; retvalue result, r; result = RET_NOTHING; for (i = 0 ; i < filekeys->count ; i++) { r = table_checkrecord(rdb_references, filekeys->values[i], referee); if (r == RET_NOTHING) { fprintf(stderr, "Missing reference to '%s' by '%s'\n", filekeys->values[i], referee); r = RET_ERROR; } RET_UPDATE(result, r); } return result; }
static inline retvalue trackedpackage_removeall(trackingdb tracks, struct trackedpackage *pkg) { retvalue result = RET_OK, r; char *id; // printf("[trackedpackage_removeall %s %s %s]\n", tracks->codename, pkg->sourcename, pkg->sourceversion); id = calc_trackreferee(tracks->codename, pkg->sourcename, pkg->sourceversion); if (FAILEDTOALLOC(id)) return RET_ERROR_OOM; pkg->flags.deleted = true; r = references_delete(id, &pkg->filekeys, NULL); RET_UPDATE(result, r); free(id); strlist_done(&pkg->filekeys); strlist_init(&pkg->filekeys); free(pkg->refcounts); pkg->refcounts = NULL; return result; }
/* Remove reference by <identifer> for the given <oldfiles>, * excluding <exclude>, if it is nonNULL. */ retvalue references_delete(const char *identifier, struct strlist *files, const struct strlist *exclude) { retvalue result, r; int i; assert (files != NULL); result = RET_NOTHING; for (i = 0 ; i < files->count ; i++) { const char *filekey = files->values[i]; if (exclude == NULL || !strlist_in(exclude, filekey)) { r = references_decrement(filekey, identifier); RET_UPDATE(result, r); } } return result; }
retvalue pull_dumpupdate(struct pull_distribution *distributions) { struct pull_distribution *d; retvalue result, r; for (d=distributions ; d != NULL ; d=d->next) { r = distribution_loadalloverrides(d->distribution); if (RET_WAS_ERROR(r)) return r; } result = RET_NOTHING; for (d=distributions ; d != NULL ; d=d->next) { r = pull_search(NULL, d); RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) break; pull_dumplist(d); } return result; }
/* remove reference for a file from a given reference */ retvalue references_decrement(const char *needed, const char *neededby) { retvalue r; r = table_removerecord(rdb_references, needed, neededby); if (r == RET_NOTHING) return r; if (RET_WAS_ERROR(r)) { fprintf(stderr, "Error while trying to removing reference to '%s' by '%s'\n", needed, neededby); return r; } if (verbose > 8) fprintf(stderr, "Removed reference to '%s' by '%s'\n", needed, neededby); if (RET_IS_OK(r)) { retvalue r2; r2 = pool_dereferenced(needed); RET_UPDATE(r, r2); } return r; }