diff options
Diffstat (limited to '')
-rw-r--r-- | checkindsc.c | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/checkindsc.c b/checkindsc.c new file mode 100644 index 0000000..43fa5f2 --- /dev/null +++ b/checkindsc.c @@ -0,0 +1,435 @@ +/* This file is part of "reprepro" + * Copyright (C) 2003,2004,2005,2006,2007,2008,2012 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 <config.h> + +#include <errno.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> +#include <string.h> +#include <ctype.h> +#include "error.h" +#include "filecntl.h" +#include "strlist.h" +#include "checksums.h" +#include "names.h" +#include "checksums.h" +#include "dirs.h" +#include "checkindsc.h" +#include "reference.h" +#include "sources.h" +#include "files.h" +#include "guesscomponent.h" +#include "tracking.h" +#include "ignore.h" +#include "override.h" +#include "log.h" +#include "sourceextraction.h" + +/* This file includes the code to include sources, i.e. + to create the chunk for the Sources.gz-file and + to put it in the various databases. + +things to do with .dsc's checkin by hand: (by comparison with apt-ftparchive) +* Get all from .dsc (search the chunk with + the Source:-field. end the chunk artificial + before the pgp-end-block.(in case someone + missed the newline there)) + +* check to have source, version, maintainer, + standards-version, files. And also look + at binary, architecture and build*, as + described in policy 5.4 + +* Get overwrite information, especially + the priority(if there is a binaries field, + check the one with the highest) and the section + (...what else...?) + +* Rename Source-Field to Package-Field + +* add dsc to files-list. (check other files md5sum and size) + +* add Directory-field + +* Add Priority and Status + +* apply possible maintainer-updates from the overwrite-file + or arbitrary tag changes from the extra-overwrite-file + +* keep rest (perhaps sort alphabetical) + +*/ + +struct dscpackage { + /* things to be set by dsc_read: */ + struct dsc_headers dsc; + /* things that will still be NULL then: */ + component_t component; + /* Things that may be calculated by dsc_calclocations: */ + struct strlist filekeys; +}; + +static void dsc_free(/*@only@*/struct dscpackage *pkg) { + if (pkg != NULL) { + sources_done(&pkg->dsc); + strlist_done(&pkg->filekeys); + free(pkg); + } +} + +static retvalue dsc_read(/*@out@*/struct dscpackage **pkg, const char *filename) { + retvalue r; + struct dscpackage *dsc; + bool broken; + + + dsc = zNEW(struct dscpackage); + if (FAILEDTOALLOC(dsc)) + return RET_ERROR_OOM; + + r = sources_readdsc(&dsc->dsc, filename, filename, &broken); + if (RET_IS_OK(r) && broken && !IGNORING(brokensignatures, +"'%s' contains only broken signatures.\n" +"This most likely means the file was damaged or edited improperly\n", + filename)) + r = RET_ERROR; + if (RET_IS_OK(r)) + r = propersourcename(dsc->dsc.name); + if (RET_IS_OK(r)) + r = properversion(dsc->dsc.version); + if (RET_IS_OK(r)) + r = properfilenames(&dsc->dsc.files.names); + if (RET_WAS_ERROR(r)) { + dsc_free(dsc); + return r; + } + dsc->component = atom_unknown; + *pkg = dsc; + + return RET_OK; +} + +retvalue dsc_addprepared(const struct dsc_headers *dsc, component_t component, const struct strlist *filekeys, struct distribution *distribution, struct trackingdata *trackingdata){ + retvalue r; + struct target *t = distribution_getpart(distribution, + component, architecture_source, pt_dsc); + + assert (logger_isprepared(distribution->logger)); + + /* finally put it into the source distribution */ + r = target_initpackagesdb(t, READWRITE); + if (!RET_WAS_ERROR(r)) { + retvalue r2; + if (interrupted()) + r = RET_ERROR_INTERRUPTED; + else + r = target_addpackage(t, distribution->logger, + dsc->name, dsc->version, + dsc->control, filekeys, + false, trackingdata, + architecture_source, + NULL, NULL); + r2 = target_closepackagesdb(t); + RET_ENDUPDATE(r, r2); + } + RET_UPDATE(distribution->status, r); + return r; +} + +/* insert the given .dsc into the mirror in <component> in the <distribution> + * if component is NULL, guessing it from the section. + * If basename, filekey and directory are != NULL, then they are used instead + * of being newly calculated. + * (And all files are expected to already be in the pool). */ +retvalue dsc_add(component_t forcecomponent, const char *forcesection, const char *forcepriority, struct distribution *distribution, const char *dscfilename, int delete, trackingdb tracks){ + retvalue r; + struct dscpackage *pkg; + struct trackingdata trackingdata; + char *destdirectory, *origdirectory; + const struct overridedata *oinfo; + char *control; + int i; + + causingfile = dscfilename; + + /* First make sure this distribution has a source section at all, + * for which it has to be listed in the "Architectures:"-field ;-) */ + if (!atomlist_in(&distribution->architectures, architecture_source)) { + fprintf(stderr, +"Cannot put a source package into Distribution '%s' not having 'source' in its 'Architectures:'-field!\n", + distribution->codename); + /* nota bene: this cannot be forced or ignored, as no target has + been created for this. */ + return RET_ERROR; + } + + r = dsc_read(&pkg, dscfilename); + if (RET_WAS_ERROR(r)) { + return r; + } + + oinfo = override_search(distribution->overrides.dsc, pkg->dsc.name); + if (forcesection == NULL) { + forcesection = override_get(oinfo, SECTION_FIELDNAME); + } + if (forcepriority == NULL) { + forcepriority = override_get(oinfo, PRIORITY_FIELDNAME); + } + + if (forcesection != NULL) { + free(pkg->dsc.section); + pkg->dsc.section = strdup(forcesection); + if (FAILEDTOALLOC(pkg->dsc.section)) { + dsc_free(pkg); + return RET_ERROR_OOM; + } + } + if (forcepriority != NULL) { + free(pkg->dsc.priority); + pkg->dsc.priority = strdup(forcepriority); + if (FAILEDTOALLOC(pkg->dsc.priority)) { + dsc_free(pkg); + return RET_ERROR_OOM; + } + } + + r = dirs_getdirectory(dscfilename, &origdirectory); + if (RET_WAS_ERROR(r)) { + dsc_free(pkg); + return r; + } + + if (pkg->dsc.section == NULL || pkg->dsc.priority == NULL) { + struct sourceextraction *extraction; + + extraction = sourceextraction_init( + (pkg->dsc.section == NULL)?&pkg->dsc.section:NULL, + (pkg->dsc.priority == NULL)?&pkg->dsc.priority:NULL); + if (FAILEDTOALLOC(extraction)) { + free(origdirectory); + dsc_free(pkg); + return RET_ERROR_OOM; + } + for (i = 0 ; i < pkg->dsc.files.names.count ; i ++) + sourceextraction_setpart(extraction, i, + pkg->dsc.files.names.values[i]); + while (sourceextraction_needs(extraction, &i)) { + char *fullfilename = calc_dirconcat(origdirectory, + pkg->dsc.files.names.values[i]); + if (FAILEDTOALLOC(fullfilename)) { + free(origdirectory); + dsc_free(pkg); + return RET_ERROR_OOM; + } + /* while it would nice to try at the pool if we + * do not have the file here, to know its location + * in the pool we need to know the component. And + * for the component we might need the section first */ + // TODO: but if forcecomponent is set it might be possible. + r = sourceextraction_analyse(extraction, fullfilename); + free(fullfilename); + if (RET_WAS_ERROR(r)) { + free(origdirectory); + dsc_free(pkg); + sourceextraction_abort(extraction); + return r; + } + } + r = sourceextraction_finish(extraction); + if (RET_WAS_ERROR(r)) { + free(origdirectory); + dsc_free(pkg); + return r; + } + } + + if (pkg->dsc.section == NULL && pkg->dsc.priority == NULL) { + fprintf(stderr, +"No section and no priority for '%s', skipping.\n", + pkg->dsc.name); + free(origdirectory); + dsc_free(pkg); + return RET_ERROR; + } + if (pkg->dsc.section == NULL) { + fprintf(stderr, "No section for '%s', skipping.\n", + pkg->dsc.name); + free(origdirectory); + dsc_free(pkg); + return RET_ERROR; + } + if (pkg->dsc.priority == NULL) { + fprintf(stderr, "No priority for '%s', skipping.\n", + pkg->dsc.name); + free(origdirectory); + dsc_free(pkg); + return RET_ERROR; + } + if (strcmp(pkg->dsc.section, "unknown") == 0 && verbose >= 0) { + fprintf(stderr, "Warning: strange section '%s'!\n", + pkg->dsc.section); + } + if (!atom_defined(forcecomponent)) { + const char *fc; + + fc = override_get(oinfo, "$Component"); + if (fc != NULL) { + forcecomponent = component_find(fc); + if (!atom_defined(forcecomponent)) { + fprintf(stderr, +"Unparseable component '%s' in $Component override of '%s'\n", + fc, pkg->dsc.name); + return RET_ERROR; + } + } + } + + /* decide where it has to go */ + + r = guess_component(distribution->codename, &distribution->components, + pkg->dsc.name, pkg->dsc.section, forcecomponent, + &pkg->component); + if (RET_WAS_ERROR(r)) { + free(origdirectory); + dsc_free(pkg); + return r; + } + if (verbose > 0 && !atom_defined(forcecomponent)) { + fprintf(stderr, "%s: component guessed as '%s'\n", dscfilename, + atoms_components[pkg->component]); + } + + { char *dscbasename, *dscfilekey; + struct checksums *dscchecksums; + + dscbasename = calc_source_basename(pkg->dsc.name, pkg->dsc.version); + destdirectory = calc_sourcedir(pkg->component, pkg->dsc.name); + /* Calculate the filekeys: */ + if (destdirectory != NULL) + r = calc_dirconcats(destdirectory, + &pkg->dsc.files.names, + &pkg->filekeys); + if (dscbasename == NULL || destdirectory == NULL || RET_WAS_ERROR(r)) { + free(dscbasename); + free(destdirectory); free(origdirectory); + dsc_free(pkg); + return r; + } + dscfilekey = calc_dirconcat(destdirectory, dscbasename); + dscchecksums = NULL; + if (FAILEDTOALLOC(dscfilename)) + r = RET_ERROR_OOM; + else + /* then look if we already have this, or copy it in */ + r = files_preinclude( + dscfilename, dscfilekey, + &dscchecksums); + + if (!RET_WAS_ERROR(r)) { + /* Add the dsc-file to basenames, filekeys and md5sums, + * so that it will be listed in the Sources.gz */ + + r = checksumsarray_include(&pkg->dsc.files, + dscbasename, dscchecksums); + if (RET_IS_OK(r)) + r = strlist_include(&pkg->filekeys, dscfilekey); + else + free(dscfilekey); + } else { + free(dscfilekey); + free(dscbasename); + } + checksums_free(dscchecksums); + } + + assert (pkg->dsc.files.names.count == pkg->filekeys.count); + for (i = 1 ; i < pkg->dsc.files.names.count ; i ++) { + if (!RET_WAS_ERROR(r)) { + r = files_checkincludefile(origdirectory, + pkg->dsc.files.names.values[i], + pkg->filekeys.values[i], + &pkg->dsc.files.checksums[i]); + } + } + + /* Calculate the chunk to include: */ + + if (!RET_WAS_ERROR(r)) + r = sources_complete(&pkg->dsc, destdirectory, oinfo, + pkg->dsc.section, pkg->dsc.priority, &control); + free(destdirectory); + if (RET_IS_OK(r)) { + free(pkg->dsc.control); + pkg->dsc.control = control; + } else { + free(origdirectory); + dsc_free(pkg); + return r; + } + + if (interrupted()) { + dsc_free(pkg); + free(origdirectory); + return RET_ERROR_INTERRUPTED; + } + + if (tracks != NULL) { + r = trackingdata_summon(tracks, pkg->dsc.name, + pkg->dsc.version, &trackingdata); + if (RET_WAS_ERROR(r)) { + free(origdirectory); + dsc_free(pkg); + return r; + } + } + + r = dsc_addprepared(&pkg->dsc, pkg->component, + &pkg->filekeys, distribution, + (tracks!=NULL)?&trackingdata:NULL); + + /* delete source files, if they are to be */ + if ((RET_IS_OK(r) && delete >= D_MOVE) || + (r == RET_NOTHING && delete >= D_DELETE)) { + char *fullfilename; + + for (i = 0 ; i < pkg->dsc.files.names.count ; i++) { + fullfilename = calc_dirconcat(origdirectory, + pkg->dsc.files.names.values[i]); + if (FAILEDTOALLOC(fullfilename)) { + r = RET_ERROR_OOM; + break; + } + if (isregularfile(fullfilename)) + deletefile(fullfilename); + free(fullfilename); + } + } + free(origdirectory); + dsc_free(pkg); + + if (tracks != NULL) { + retvalue r2; + r2 = trackingdata_finish(tracks, &trackingdata); + RET_ENDUPDATE(r, r2); + } + return r; +} |