From 4b8a0f3f3dcf60dac2ce308ea08d413a535af29f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 21:12:14 +0200 Subject: Adding upstream version 5.4.4. Signed-off-by: Daniel Baumann --- sources.c | 733 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 733 insertions(+) create mode 100644 sources.c (limited to 'sources.c') diff --git a/sources.c b/sources.c new file mode 100644 index 0000000..1e7efcb --- /dev/null +++ b/sources.c @@ -0,0 +1,733 @@ +/* This file is part of "reprepro" + * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Bernhard R. Link + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "error.h" +#include "mprintf.h" +#include "strlist.h" +#include "chunks.h" +#include "sources.h" +#include "names.h" +#include "dirs.h" +#include "dpkgversions.h" +#include "override.h" +#include "tracking.h" +#include "signature.h" +#include "package.h" + +/* split a " " into md5sum and filename */ +static retvalue calc_parsefileline(const char *fileline, /*@out@*/char **filename) { + const char *p, *fn, *fnend; + char *filen; + + assert (fileline != NULL); + if (*fileline == '\0') + return RET_NOTHING; + + /* the md5sums begins after the (perhaps) heading spaces ... */ + p = fileline; + while (*p != '\0' && (*p == ' ' || *p == '\t')) + p++; + if (*p == '\0') + return RET_NOTHING; + /* ... and ends with the following spaces. */ + while (*p != '\0' && !(*p == ' ' || *p == '\t')) + p++; + if (*p == '\0') { + fprintf(stderr, "Expecting more data after md5sum!\n"); + return RET_ERROR; + } + /* Then the size of the file is expected: */ + while ((*p == ' ' || *p == '\t')) + p++; + while (*p !='\0' && !(*p == ' ' || *p == '\t')) + p++; + if (*p == '\0') { + fprintf(stderr, "Expecting more data after size!\n"); + return RET_ERROR; + } + /* Then the filename */ + fn = p; + while ((*fn == ' ' || *fn == '\t')) + fn++; + fnend = fn; + while (*fnend != '\0' && !(*fnend == ' ' || *fnend == '\t')) + fnend++; + + filen = strndup(fn, fnend-fn); + if (FAILEDTOALLOC(filen)) + return RET_ERROR_OOM; + *filename = filen; + return RET_OK; +} + +static retvalue getBasenames(const struct strlist *filelines, /*@out@*/struct strlist *basenames) { + int i; + retvalue r; + + assert (filelines != NULL && basenames != NULL); + + r = strlist_init_n(filelines->count, basenames); + if (RET_WAS_ERROR(r)) + return r; + r = RET_NOTHING; + for (i = 0 ; i < filelines->count ; i++) { + char *basefilename; + const char *fileline = filelines->values[i]; + + r = calc_parsefileline(fileline, &basefilename); + if (r == RET_NOTHING) { + fprintf(stderr, "Malformed Files: line '%s'!\n", + fileline); + r = RET_ERROR; + } + if (RET_WAS_ERROR(r)) + break; + + r = strlist_add(basenames, basefilename); + if (RET_WAS_ERROR(r)) { + break; + } + r = RET_OK; + } + if (RET_WAS_ERROR(r)) { + strlist_done(basenames); + } else { + assert (filelines->count == basenames->count); + } + return r; +} + +retvalue sources_getversion(const char *control, char **version) { + retvalue r; + + r = chunk_getvalue(control, "Version", version); + if (RET_WAS_ERROR(r)) + return r; + if (r == RET_NOTHING) { + fprintf(stderr, "Missing 'Version' field in chunk:'%s'\n", + control); + return RET_ERROR; + } + return r; +} + +retvalue sources_getarchitecture(UNUSED(const char *chunk), architecture_t *architecture_p) { + *architecture_p = architecture_source; + return RET_OK; +} + +retvalue sources_getinstalldata(const struct target *t, struct package *package, char **control, struct strlist *filekeys, struct checksumsarray *origfiles) { + retvalue r; + char *origdirectory, *directory, *mychunk; + struct strlist myfilekeys; + struct strlist filelines[cs_hashCOUNT]; + struct checksumsarray files; + enum checksumtype cs; + bool gothash = false; + const char *chunk = package->control; + + assert (package->architecture == architecture_source); + + for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) { + assert (source_checksum_names[cs] != NULL); + r = chunk_getextralinelist(chunk, source_checksum_names[cs], + &filelines[cs]); + if (r == RET_NOTHING) + strlist_init(&filelines[cs]); + else if (RET_WAS_ERROR(r)) { + while (cs-- > cs_md5sum) { + strlist_done(&filelines[cs]); + } + return r; + } 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; + } + r = checksumsarray_parse(&files, filelines, package->name); + for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) { + strlist_done(&filelines[cs]); + } + if (RET_WAS_ERROR(r)) + return r; + + r = chunk_getvalue(chunk, "Directory", &origdirectory); + if (r == RET_NOTHING) { +/* Flat repositories can come without this, TODO: add warnings in other cases + fprintf(stderr, "Missing 'Directory' entry in '%s'!\n", chunk); + r = RET_ERROR; +*/ + origdirectory = strdup("."); + if (FAILEDTOALLOC(origdirectory)) + r = RET_ERROR_OOM; + } + if (RET_WAS_ERROR(r)) { + checksumsarray_done(&files); + return r; + } + + r = propersourcename(package->name); + assert (r != RET_NOTHING); + if (RET_IS_OK(r)) + r = properfilenames(&files.names); + if (RET_WAS_ERROR(r)) { + fprintf(stderr, +"Forbidden characters in source package '%s'!\n", package->name); + free(origdirectory); + checksumsarray_done(&files); + return r; + } + + directory = calc_sourcedir(t->component, package->name); + if (FAILEDTOALLOC(directory)) + r = RET_ERROR_OOM; + else + r = calc_dirconcats(directory, &files.names, &myfilekeys); + if (RET_WAS_ERROR(r)) { + free(directory); + free(origdirectory); + checksumsarray_done(&files); + return r; + } + r = calc_inplacedirconcats(origdirectory, &files.names); + free(origdirectory); + if (!RET_WAS_ERROR(r)) { + char *n; + + n = chunk_normalize(chunk, "Package", package->name); + if (FAILEDTOALLOC(n)) + mychunk = NULL; + else + mychunk = chunk_replacefield(n, + "Directory", directory, true); + free(n); + if (FAILEDTOALLOC(mychunk)) + r = RET_ERROR_OOM; + } + free(directory); + if (RET_WAS_ERROR(r)) { + strlist_done(&myfilekeys); + checksumsarray_done(&files); + return r; + } + *control = mychunk; + strlist_move(filekeys, &myfilekeys); + checksumsarray_move(origfiles, &files); + return RET_OK; +} + +retvalue sources_getfilekeys(const char *chunk, struct strlist *filekeys) { + char *origdirectory; + struct strlist basenames; + retvalue r; + struct strlist filelines; + + + /* Read the directory given there */ + r = chunk_getvalue(chunk, "Directory", &origdirectory); + if (r == RET_NOTHING) { + //TODO: check if it is even text and do not print + //of looking binary?? + fprintf(stderr, "Does not look like source control: '%s'\n", + chunk); + return RET_ERROR; + } + if (RET_WAS_ERROR(r)) + return r; + + r = chunk_getextralinelist(chunk, "Files", &filelines); + if (r == RET_NOTHING) { + //TODO: check if it is even text and do not print + //of looking binary?? + fprintf(stderr, "Does not look like source control: '%s'\n", + chunk); + r = RET_ERROR; + } + if (RET_WAS_ERROR(r)) { + free(origdirectory); + return r; + } + r = getBasenames(&filelines, &basenames); + strlist_done(&filelines); + if (RET_WAS_ERROR(r)) { + free(origdirectory); + return r; + } + + r = calc_dirconcats(origdirectory, &basenames, filekeys); + free(origdirectory); + strlist_done(&basenames); + return r; +} + +retvalue sources_getchecksums(const char *chunk, struct checksumsarray *out) { + char *origdirectory; + struct checksumsarray a; + retvalue r; + struct strlist filelines[cs_hashCOUNT]; + enum checksumtype cs; + + /* Read the directory given there */ + r = chunk_getvalue(chunk, "Directory", &origdirectory); + if (!RET_IS_OK(r)) + return r; + + for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) { + assert (source_checksum_names[cs] != NULL); + r = chunk_getextralinelist(chunk, source_checksum_names[cs], + &filelines[cs]); + if (r == RET_NOTHING) { + if (cs == cs_md5sum) { + fprintf(stderr, +"Missing 'Files' entry in '%s'!\n", + chunk); + r = RET_ERROR; + } else + strlist_init(&filelines[cs]); + } + if (RET_WAS_ERROR(r)) { + while (cs-- > cs_md5sum) { + strlist_done(&filelines[cs]); + } + free(origdirectory); + return r; + } + } + r = checksumsarray_parse(&a, filelines, "source chunk"); + for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) { + strlist_done(&filelines[cs]); + } + if (RET_WAS_ERROR(r)) { + free(origdirectory); + return r; + } + + r = calc_inplacedirconcats(origdirectory, &a.names); + free(origdirectory); + if (RET_WAS_ERROR(r)) { + checksumsarray_done(&a); + return r; + } + checksumsarray_move(out, &a); + return RET_OK; +} + +retvalue sources_doreoverride(const struct target *target, const char *packagename, const char *controlchunk, /*@out@*/char **newcontrolchunk) { + const struct overridedata *o; + struct fieldtoadd *fields; + char *newchunk; + retvalue r; + + if (interrupted()) + return RET_ERROR_INTERRUPTED; + + o = override_search(target->distribution->overrides.dsc, packagename); + if (o == NULL) + return RET_NOTHING; + + r = override_allreplacefields(o, &fields); + if (!RET_IS_OK(r)) + return r; + newchunk = chunk_replacefields(controlchunk, fields, + "Directory", true); + addfield_free(fields); + if (FAILEDTOALLOC(newchunk)) + return RET_ERROR_OOM; + *newcontrolchunk = newchunk; + return RET_OK; +} + +retvalue sources_retrack(const char *sourcename, const char *chunk, trackingdb tracks) { + retvalue r; + char *sourceversion; + struct trackedpackage *pkg; + struct strlist filekeys; + int i; + + //TODO: eliminate duplicate code! + assert(sourcename!=NULL); + + if (interrupted()) + return RET_ERROR_INTERRUPTED; + + r = chunk_getvalue(chunk, "Version", &sourceversion); + if (r == RET_NOTHING) { + fprintf(stderr, "Missing 'Version' field in chunk:'%s'\n", + chunk); + r = RET_ERROR; + } + if (RET_WAS_ERROR(r)) { + return r; + } + + r = sources_getfilekeys(chunk, &filekeys); + if (r == RET_NOTHING) { + fprintf(stderr, "Malformed source control:'%s'\n", chunk); + r = RET_ERROR; + } + if (RET_WAS_ERROR(r)) { + free(sourceversion); + return r; + } + + r = tracking_getornew(tracks, sourcename, sourceversion, &pkg); + free(sourceversion); + if (RET_WAS_ERROR(r)) { + strlist_done(&filekeys); + return r; + } + + // TODO: error handling is suboptimal here. + // is there a way to again remove old additions (esp. references) + // where something fails? + for (i = 0 ; i < filekeys.count ; i++) { + r = trackedpackage_addfilekey(tracks, pkg, + ft_SOURCE, filekeys.values[i], true); + filekeys.values[i] = NULL; + if (RET_WAS_ERROR(r)) { + strlist_done(&filekeys); + trackedpackage_free(pkg); + return r; + } + } + strlist_done(&filekeys); + return tracking_save(tracks, pkg); +} + +retvalue sources_getsourceandversion(const char *chunk, const char *packagename, char **source, char **version) { + retvalue r; + char *sourceversion; + char *sourcename; + + //TODO: eliminate duplicate code! + assert(packagename!=NULL); + + r = chunk_getvalue(chunk, "Version", &sourceversion); + if (r == RET_NOTHING) { + fprintf(stderr, "Missing 'Version' field in chunk:'%s'\n", + chunk); + r = RET_ERROR; + } + if (RET_WAS_ERROR(r)) { + return r; + } + sourcename = strdup(packagename); + if (FAILEDTOALLOC(sourcename)) { + free(sourceversion); + return RET_ERROR_OOM; + } + *source = sourcename; + *version = sourceversion; + return RET_OK; +} + +/****************************************************************/ + +static inline retvalue getvalue(const char *filename, const char *chunk, const char *field, char **value) { + retvalue r; + + r = chunk_getvalue(chunk, field, value); + if (r == RET_NOTHING) { + fprintf(stderr, "Missing '%s' field in %s!\n", + field, filename); + r = RET_ERROR; + } + return r; +} + +static inline retvalue checkvalue(const char *filename, const char *chunk, const char *field) { + retvalue r; + + r = chunk_checkfield(chunk, field); + if (r == RET_NOTHING) { + fprintf(stderr, "Cannot find '%s' field in %s!\n", + field, filename); + r = RET_ERROR; + } + return r; +} + +static inline retvalue getvalue_n(const char *chunk, const char *field, char **value) { + retvalue r; + + r = chunk_getvalue(chunk, field, value); + if (r == RET_NOTHING) { + *value = NULL; + } + return r; +} + +retvalue sources_readdsc(struct dsc_headers *dsc, const char *filename, const char *filenametoshow, bool *broken) { + retvalue r; + struct strlist filelines[cs_hashCOUNT]; + enum checksumtype cs; + + r = signature_readsignedchunk(filename, filenametoshow, + &dsc->control, NULL, broken); + if (RET_WAS_ERROR(r)) { + return r; + } + if (verbose > 100) { + fprintf(stderr, "Extracted control chunk from '%s': '%s'\n", + filenametoshow, dsc->control); + } + + /* first look for fields that should be there */ + + r = chunk_getname(dsc->control, "Source", &dsc->name, false); + if (r == RET_NOTHING) { + fprintf(stderr, "Missing 'Source' field in %s!\n", + filenametoshow); + return RET_ERROR; + } + if (RET_WAS_ERROR(r)) + return r; + + /* This is needed and cannot be ignored unless + * sources_complete is changed to not need it */ + r = checkvalue(filenametoshow, dsc->control, "Format"); + if (RET_WAS_ERROR(r)) + return r; + + r = checkvalue(filenametoshow, dsc->control, "Maintainer"); + if (RET_WAS_ERROR(r)) + return r; + + r = getvalue(filenametoshow, dsc->control, "Version", &dsc->version); + if (RET_WAS_ERROR(r)) + return r; + + r = getvalue_n(dsc->control, SECTION_FIELDNAME, &dsc->section); + if (RET_WAS_ERROR(r)) + return r; + r = getvalue_n(dsc->control, PRIORITY_FIELDNAME, &dsc->priority); + if (RET_WAS_ERROR(r)) + return r; + + for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) { + assert (source_checksum_names[cs] != NULL); + r = chunk_getextralinelist(dsc->control, + source_checksum_names[cs], &filelines[cs]); + if (r == RET_NOTHING) { + if (cs == cs_md5sum) { + fprintf(stderr, +"Missing 'Files' field in '%s'!\n", + filenametoshow); + r = RET_ERROR; + } else + strlist_init(&filelines[cs]); + } + if (RET_WAS_ERROR(r)) { + while (cs-- > cs_md5sum) { + strlist_done(&filelines[cs]); + } + return r; + } + } + r = checksumsarray_parse(&dsc->files, filelines, filenametoshow); + for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) { + strlist_done(&filelines[cs]); + } + return r; +} + +void sources_done(struct dsc_headers *dsc) { + free(dsc->name); + free(dsc->version); + free(dsc->control); + checksumsarray_done(&dsc->files); + free(dsc->section); + free(dsc->priority); +} + +retvalue sources_complete(const struct dsc_headers *dsc, const char *directory, const struct overridedata *override, const char *section, const char *priority, char **newcontrol) { + retvalue r; + struct fieldtoadd *replace; + char *newchunk, *newchunk2; + char *newfilelines, *newsha1lines, *newsha256lines; + + assert(section != NULL && priority != NULL); + + newchunk2 = chunk_normalize(dsc->control, "Package", dsc->name); + if (FAILEDTOALLOC(newchunk2)) + return RET_ERROR_OOM; + + r = checksumsarray_genfilelist(&dsc->files, + &newfilelines, &newsha1lines, &newsha256lines); + if (RET_WAS_ERROR(r)) { + free(newchunk2); + return r; + } + assert (newfilelines != NULL); + replace = aodfield_new("Checksums-Sha256", newsha256lines, NULL); + if (!FAILEDTOALLOC(replace)) + replace = aodfield_new("Checksums-Sha1", newsha1lines, replace); + if (!FAILEDTOALLOC(replace)) + replace = deletefield_new("Source", replace); + if (!FAILEDTOALLOC(replace)) + replace = addfield_new("Files", newfilelines, replace); + 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)) { + free(newsha256lines); + free(newsha1lines); + free(newfilelines); + free(newchunk2); + return RET_ERROR_OOM; + } + + newchunk = chunk_replacefields(newchunk2, replace, "Files", true); + free(newsha256lines); + free(newsha1lines); + free(newfilelines); + free(newchunk2); + addfield_free(replace); + if (FAILEDTOALLOC(newchunk)) { + return RET_ERROR_OOM; + } + + *newcontrol = newchunk; + + return RET_OK; +} + +/* 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; + checksums.names.values = nzNEW(filekeys->count, char *); + if (FAILEDTOALLOC(checksums.names.values)) + return RET_ERROR_OOM; + for (i = 0 ; i < filekeys->count ; i++) { + checksums.names.values[i] = (char*) + dirs_basename(filekeys->values[i]); + } + + r = checksumsarray_genfilelist(&checksums, + &newfilelines, &newsha1lines, &newsha256lines); + free(checksums.names.values); + if (RET_WAS_ERROR(r)) + return r; + assert (newfilelines != NULL); + replace = aodfield_new("Checksums-Sha256", newsha256lines, NULL); + if (!FAILEDTOALLOC(replace)) + replace = aodfield_new("Checksums-Sha1", newsha1lines, replace); + if (!FAILEDTOALLOC(replace)) + replace = addfield_new("Files", newfilelines, replace); + if (FAILEDTOALLOC(replace)) { + free(newsha256lines); + free(newsha1lines); + free(newfilelines); + return RET_ERROR_OOM; + } + newchunk = chunk_replacefields(chunk, replace, "Files", true); + free(newsha256lines); + free(newsha1lines); + free(newfilelines); + addfield_free(replace); + if (FAILEDTOALLOC(newchunk)) + return RET_ERROR_OOM; + + *out = newchunk; + return RET_OK; +} + +char *calc_source_basename(const char *name, const char *version) { + const char *v = strchr(version, ':'); + if (v != NULL) + v++; + else + v = version; + return mprintf("%s_%s.dsc", name, v); +} + +char *calc_sourcedir(component_t component, const char *sourcename) { + + assert (*sourcename != '\0'); + + if (sourcename[0] == 'l' && sourcename[1] == 'i' && + sourcename[2] == 'b' && sourcename[3] != '\0') + return mprintf("pool/%s/lib%c/%s", + atoms_components[component], + sourcename[3], sourcename); + else if (*sourcename != '\0') + 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) { + if (sourcename[0] == 'l' && sourcename[1] == 'i' && + sourcename[2] == 'b' && sourcename[3] != '\0') + return mprintf("pool/%s/lib%c/%s/%s", + atoms_components[component], + sourcename[3], sourcename, filename); + else if (*sourcename != '\0') + return mprintf("pool/%s/%c/%s/%s", + atoms_components[component], + sourcename[0], sourcename, filename); + else + return NULL; +} + +char *calc_byhanddir(component_t component, const char *sourcename, const char *version) { + if (sourcename[0] == 'l' && sourcename[1] == 'i' && + sourcename[2] == 'b' && sourcename[3] != '\0') + return mprintf("pool/%s/lib%c/%s/%s_%s_byhand", + atoms_components[component], + sourcename[3], sourcename, + sourcename, version); + else if (*sourcename != '\0') + return mprintf("pool/%s/%c/%s/%s_%s_byhand", + atoms_components[component], + sourcename[0], sourcename, + sourcename, version); + else + return NULL; +} -- cgit v1.2.3