/* 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 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; }
/* read the data from a .deb, make some checks and extract some data */ static retvalue deb_read(/*@out@*/struct debpackage **pkg, const char *filename, bool needssourceversion) { retvalue r; struct debpackage *deb; deb = zNEW(struct debpackage); if (FAILEDTOALLOC(deb)) return RET_ERROR_OOM; r = binaries_readdeb(&deb->deb, filename, needssourceversion); if (RET_IS_OK(r)) r = properpackagename(deb->deb.name); if (RET_IS_OK(r)) r = propersourcename(deb->deb.source); if (RET_IS_OK(r) && needssourceversion) r = properversion(deb->deb.sourceversion); if (RET_IS_OK(r)) r = properversion(deb->deb.version); if (RET_WAS_ERROR(r)) { deb_free(deb); return r; } *pkg = deb; return RET_OK; }
retvalue getfilelist(/*@out@*/char **filelist, size_t *size, const char *debfile) { struct ar_archive *ar; retvalue r; bool hadcandidate = false; r = ar_open(&ar, debfile); if (RET_WAS_ERROR(r)) return r; assert (r != RET_NOTHING); do { char *filename; enum compression c; r = ar_nextmember(ar, &filename); if (RET_IS_OK(r)) { if (strncmp(filename, "data.tar", 8) != 0) { free(filename); continue; } hadcandidate = true; for (c = 0 ; c < c_COUNT ; c++) { if (strcmp(filename + 8, uncompression_suffix[c]) == 0) break; } if (c >= c_COUNT) { free(filename); continue; } ar_archivemember_setcompression(ar, c); if (uncompression_supported(c)) { struct archive *tar; tar = archive_read_new(); r = read_data_tar(filelist, size, debfile, ar, tar); // TODO: check how to get an error message here.. archive_read_finish(tar); if (r != RET_NOTHING) { ar_close(ar); free(filename); return r; } } free(filename); } } while (RET_IS_OK(r)); ar_close(ar); if (hadcandidate) fprintf(stderr, "Could not find a suitable data.tar file within '%s'!\n", debfile); else fprintf(stderr, "Could not find a data.tar file within '%s'!\n", debfile); return RET_ERROR_MISSING; }
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; }
retvalue files_add_checksums(const char *filekey, const struct checksums *checksums) { retvalue r; const char *combined; size_t combinedlen; assert (rdb_checksums != NULL); r = checksums_getcombined(checksums, &combined, &combinedlen); if (!RET_IS_OK(r)) return r; r = table_adduniqsizedrecord(rdb_checksums, filekey, combined, combinedlen + 1, true, false); if (!RET_IS_OK(r)) return r; return pool_markadded(filekey); }
/* dump all references to stdout */ retvalue references_dump(void) { struct cursor *cursor; retvalue result, r; const char *found_to, *found_by; r = table_newglobalcursor(rdb_references, &cursor); if (!RET_IS_OK(r)) return r; result = RET_OK; while (cursor_nexttemp(rdb_references, cursor, &found_to, &found_by)) { if (fputs(found_by, stdout) == EOF || putchar(' ') == EOF || puts(found_to) == EOF) { result = RET_ERROR; break; } result = RET_OK; if (interrupted()) { result = RET_ERROR_INTERRUPTED; break; } } r = cursor_close(rdb_references, cursor); RET_ENDUPDATE(result, r); return result; }
retvalue readtextfile(const char *source, const char *sourcetoshow, char **data, size_t *len) { int fd; char *buffer; size_t bufferlen; retvalue r; int ret; fd = open(source, O_RDONLY|O_NOCTTY); if (fd < 0) { int e = errno; fprintf(stderr, "Error opening '%s': %s\n", sourcetoshow, strerror(e)); return RET_ERRNO(e); } r = readtextfilefd(fd, sourcetoshow, &buffer, &bufferlen); if (!RET_IS_OK(r)) { (void)close(fd); return r; } ret = close(fd); if (ret != 0) { int e = errno; free(buffer); fprintf(stderr, "Error reading %s: %s\n", sourcetoshow, strerror(e)); return RET_ERRNO(e); } *data = buffer; if (len != NULL) *len = bufferlen; return RET_OK; }
/* dump out all information */ retvalue files_printmd5sums(void) { 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)) { result = RET_OK; (void)fputs(filekey, stdout); (void)putchar(' '); while (*checksum == ':') { while (*checksum != ' ' && *checksum != '\0') checksum++; if (*checksum == ' ') checksum++; } (void)fputs(checksum, stdout); (void)putchar('\n'); } r = cursor_close(rdb_checksums, cursor); RET_ENDUPDATE(result, r); 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_finish(trackingdb tracks, struct trackingdata *d) { retvalue r; assert (d->tracks == tracks); if (d->pkg != NULL) { r = trackedpackage_tidy(tracks, d->pkg); r = tracking_save(tracks, d->pkg); } else r = RET_OK; d->pkg = NULL; /* call for all remembered actions... */ while (d->remembered != NULL) { struct trackingdata_remember *h = d->remembered; struct trackedpackage *pkg; d->remembered = h->next; r = tracking_get(tracks, h->name, h->version, &pkg); free(h->name); free(h->version); free(h); if (RET_IS_OK(r)) { r = trackedpackage_tidy(tracks, pkg); r = tracking_save(tracks, pkg); } } d->tracks = NULL; return r; }
retvalue files_remove(const char *filekey) { retvalue r; r = files_removesilent(filekey); if (RET_IS_OK(r)) return pool_markdeleted(filekey); return r; }
/* add an reference to a file for an identifier. multiple calls */ retvalue references_increment(const char *needed, const char *neededby) { retvalue r; r = table_addrecord(rdb_references, needed, neededby, strlen(neededby), false); if (RET_IS_OK(r) && verbose > 8) printf("Adding reference to '%s' by '%s'\n", needed, neededby); return r; }
void markdone_index(struct markdonefile *done, const char *file, const struct checksums *checksums) { retvalue r; size_t s; const char *data; r = checksums_getcombined(checksums, &data, &s); if (!RET_IS_OK(r)) return; fprintf(done->file, "Index %s %s\n", file, data); }
retvalue tracking_retrack(struct distribution *d, bool needsretrack) { struct target *t; trackingdb tracks; retvalue r, rr; if (d->tracking == dt_NONE) return RET_NOTHING; for (t = d->targets ; !needsretrack && t != NULL ; t = t->next) { if (t->staletracking) needsretrack = true; } if (!needsretrack) return RET_NOTHING; if (verbose > 0) printf("Retracking %s...\n", d->codename); r = tracking_initialize(&tracks, d, false); if (!RET_IS_OK(r)) return r; /* first forget that any package is there*/ r = tracking_reset(tracks); if (!RET_WAS_ERROR(r)) { /* add back information about actually used files */ r = distribution_foreach_package(d, atom_unknown, atom_unknown, atom_unknown, package_retrack, NULL, tracks); } if (RET_IS_OK(r)) { for (t = d->targets ; t != NULL ; t = t->next) { t->staletracking = false; } } if (!RET_WAS_ERROR(r)) { /* now remove everything no longer needed */ r = tracking_tidyall(tracks); } rr = tracking_done(tracks); RET_ENDUPDATE(r, rr); return r; }
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; }
static retvalue files_get_checksums(const char *filekey, /*@out@*/struct checksums **checksums_p) { const char *checksums; size_t checksumslen; retvalue r; r = table_gettemprecord(rdb_checksums, filekey, &checksums, &checksumslen); if (!RET_IS_OK(r)) return r; return checksums_setall(checksums_p, checksums, checksumslen); }
static bool comparesourceversion(enum term_comparison c, const struct compare_with *v, const void *d1, const void *d2) { const char *control = d1; const struct target *target = d2; char *package, *source, *version; retvalue r; bool matches; // TODO: make more efficient r = chunk_getvalue(control, "Package", &package); if (!RET_IS_OK(r)) return false; r = target->getsourceandversion(control, package, &source, &version); free(package); if (!RET_IS_OK(r)) return false; free(source); matches = compare_dpkgversions(c, version, v->pointer); free(version); return matches; }
retvalue tracking_removepackages(trackingdb t, struct distribution *distribution, const char *sourcename, /*@null@*/const char *version) { struct trackedpackage *pkg; retvalue result, r; if (version == NULL) return tracking_foreachversion(t, distribution, sourcename, removesourcepackage); result = tracking_get(t, sourcename, version, &pkg); if (RET_IS_OK(result)) { result = removesourcepackage(t, pkg, distribution); if (RET_IS_OK(result)) { r = trackedpackage_tidy(t, pkg); RET_ENDUPDATE(result, r); r = tracking_save(t, pkg); RET_ENDUPDATE(result, r); } else trackedpackage_free(pkg); } return result; }
retvalue tracking_get(trackingdb t, const char *sourcename, const char *version, /*@out@*/struct trackedpackage **pkg) { const char *data; size_t datalen; retvalue r; assert (pkg != NULL && sourcename != NULL && version != NULL); r = table_getpair(t->table, sourcename, version, &data, &datalen); if (!RET_IS_OK(r)) return r; return parse_data(sourcename, version, data, datalen, pkg); }
/* check for file in the database and if not found there, if it can be detected */ retvalue files_expect(const char *filekey, const struct checksums *checksums, bool warnifadded) { retvalue r; char *filename; struct checksums *improvedchecksums = NULL; r = files_canadd(filekey, checksums); if (r == RET_NOTHING) return RET_OK; if (RET_WAS_ERROR(r)) return r; /* ready to add means missing, so have to look for the file itself: */ filename = files_calcfullfilename(filekey); if (FAILEDTOALLOC(filename)) return RET_ERROR_OOM; /* first check if a possible manually put (or left over from previous * downloads attepts) file is there and is correct */ r = checksums_test(filename, checksums, &improvedchecksums); if (r == RET_ERROR_WRONG_MD5) { fprintf(stderr, "Deleting unexpected file '%s'!\n" "(not in database and wrong in pool)\n ", filename); if (unlink(filename) == 0) r = RET_NOTHING; else { int e = errno; fprintf(stderr, "Error %d deleting '%s': %s!\n", e, filename, strerror(e)); } } free(filename); if (!RET_IS_OK(r)) return r; if (warnifadded) fprintf(stderr, "Warning: readded existing file '%s' mysteriously missing from the checksum database.\n", filekey); // TODO: some callers might want the updated checksum when // improves is true, how to get them there? /* add found file to database */ if (improvedchecksums != NULL) { r = files_add_checksums(filekey, improvedchecksums); checksums_free(improvedchecksums); } else r = files_add_checksums(filekey, checksums); assert (r != RET_NOTHING); return r; }
off_t files_getsize(const char *filekey) { retvalue r; off_t s; struct checksums *checksums; r = files_get_checksums(filekey, &checksums); if (!RET_IS_OK(r)) return -1; s = checksums_getfilesize(checksums); checksums_free(checksums); return s; }
retvalue tracking_reset(trackingdb t) { struct cursor *cursor; retvalue result, r; struct trackedpackage *pkg; const char *key, *value, *data; char *newdata; size_t datalen, newdatalen; int i; 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)) { // this would perhaps be more stable if it just replaced // everything within the string just received... result = parse_data(key, value, data, datalen, &pkg); if (RET_WAS_ERROR(result)) break; for (i = 0 ; i < pkg->filekeys.count ; i++) { pkg->refcounts[i] = 0; } result = gen_data(pkg, &newdata, &newdatalen); trackedpackage_free(pkg); if (RET_IS_OK(result)) result = cursor_replace(t->table, cursor, newdata, newdatalen); free(newdata); if (RET_WAS_ERROR(result)) break; } r = cursor_close(t->table, cursor); RET_UPDATE(result, r); return result; }
retvalue trackingdata_summon(trackingdb tracks, const char *name, const char *version, struct trackingdata *data) { struct trackedpackage *pkg; retvalue r; r = tracking_getornew(tracks, name, version, &pkg); assert (r != RET_NOTHING); if (RET_IS_OK(r)) { data->tracks = tracks; data->pkg = pkg; data->remembered = NULL; return r; } return r; }
static bool compareversion(enum term_comparison c, const struct compare_with *v, const void *d1, const void *d2) { const char *control = d1; const struct target *target = d2; char *version; retvalue r; bool matches; r = target->getversion(control, &version); if (!RET_IS_OK(r)) return false; matches = compare_dpkgversions(c, version, v->pointer); free(version); return matches; }
/* hardlink file with known checksums and add it to database */ retvalue files_hardlinkandadd(const char *tempfile, const char *filekey, const struct checksums *checksums) { retvalue r; /* an additional check to make sure nothing tricks us into * overwriting it by another file */ r = files_canadd(filekey, checksums); if (!RET_IS_OK(r)) return r; r = checksums_hardlink(global.outdir, filekey, tempfile, checksums); if (RET_WAS_ERROR(r)) return r; return files_add_checksums(filekey, checksums); }
/***************************Input and Output****************************/ static retvalue logmessage(const struct aptmethod *method, const char *chunk, const char *type) { retvalue r; char *message; r = chunk_getvalue(chunk, "Message", &message); if (RET_WAS_ERROR(r)) return r; if (RET_IS_OK(r)) { fprintf(stderr, "aptmethod '%s': '%s'\n", method->baseuri, message); free(message); return RET_OK; } r = chunk_getvalue(chunk, "URI", &message); if (RET_WAS_ERROR(r)) return r; if (RET_IS_OK(r)) { fprintf(stderr, "aptmethod %s '%s'\n", type, message); free(message); return RET_OK; } fprintf(stderr, "aptmethod '%s': '%s'\n", method->baseuri, type); return RET_OK; }
/* check for several files in the database and update information, * return RET_NOTHING if everything is OK and nothing needs improving */ retvalue files_checkorimprove(const struct strlist *filekeys, struct checksums *checksumsarray[]) { int i; retvalue result, r; result = RET_NOTHING; for (i = 0 ; i < filekeys->count ; i++) { r = checkorimprove(filekeys->values[i], &checksumsarray[i]); if (RET_WAS_ERROR(r)) return r; if (RET_IS_OK(r)) result = RET_OK; } return result; }
retvalue tracking_foreach_ro(struct distribution *d, tracking_foreach_ro_action *action) { trackingdb t; struct cursor *cursor; retvalue result, r; struct trackedpackage *pkg; const char *key, *value, *data; size_t datalen; r = tracking_initialize(&t, d, true); if (!RET_IS_OK(r)) return r; r = table_newglobalcursor(t->table, &cursor); if (!RET_IS_OK(r)) { (void)tracking_done(t); 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)) { r = action(d, pkg); trackedpackage_free(pkg); } RET_UPDATE(result, r); if (RET_WAS_ERROR(r)) break; } r = cursor_close(t->table, cursor); RET_ENDUPDATE(result, r); r = tracking_done(t); 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; }