retvalue files_checkincludefile(const char *sourcedir, const char *basefilename, const char *filekey, struct checksums **checksums_p) { char *sourcefilename, *fullfilename; struct checksums *checksums; retvalue r; bool improves; assert (*checksums_p != NULL); r = files_get_checksums(filekey, &checksums); if (RET_WAS_ERROR(r)) return r; if (RET_IS_OK(r)) { /* there are three sources now: * - the checksums from the database (may have some we * do not even know about, and may miss some we can * generate) * - the checksums provided (typically only md5sum, * as this comes from a .changes or .dsc) * - the checksums of the file * * to make things more complicated, the file should only * be read if needed, as this needs time. * And it can happen the file got lost in the pool, then * this is the best place to replace it. */ if (!checksums_check(checksums, *checksums_p, &improves)) { fprintf(stderr, "ERROR: '%s/%s' cannot be included as '%s'.\n" "Already existing files can only be included again, if they are the same, but:\n", sourcedir, basefilename, filekey); checksums_printdifferences(stderr, checksums, *checksums_p); checksums_free(checksums); return RET_ERROR_WRONG_MD5; } r = RET_NOTHING; if (improves) r = checksums_combine(&checksums, *checksums_p, NULL); if (!RET_WAS_ERROR(r)) r = checkimproveorinclude(sourcedir, basefilename, filekey, &checksums, &improves); if (!RET_WAS_ERROR(r) && improves) r = files_replace_checksums(filekey, checksums); if (RET_IS_OK(r)) r = RET_NOTHING; /* return the combined checksum */ checksums_free(*checksums_p); *checksums_p = checksums; return r; } assert (sourcedir != NULL); sourcefilename = calc_dirconcat(sourcedir, basefilename); if (FAILEDTOALLOC(sourcefilename)) return RET_ERROR_OOM; fullfilename = files_calcfullfilename(filekey); if (FAILEDTOALLOC(fullfilename)) { free(sourcefilename); return RET_ERROR_OOM; } (void)dirs_make_parent(fullfilename); r = checksums_copyfile(fullfilename, sourcefilename, true, &checksums); if (r == RET_NOTHING) { fprintf(stderr, "Could not open '%s'!\n", sourcefilename); r = RET_ERROR_MISSING; } if (RET_WAS_ERROR(r)) { free(fullfilename); free(sourcefilename); return r; } if (!checksums_check(*checksums_p, checksums, &improves)) { deletefile(fullfilename); fprintf(stderr, "ERROR: Unexpected content of file '%s'!\n", sourcefilename); checksums_printdifferences(stderr, *checksums_p, checksums); r = RET_ERROR_WRONG_MD5; } free(sourcefilename); free(fullfilename); if (RET_WAS_ERROR(r)) { return r; } if (improves) { r = checksums_combine(checksums_p, checksums, NULL); checksums_free(checksums); if (RET_WAS_ERROR(r)) return r; } else checksums_free(checksums); return files_add_checksums(filekey, *checksums_p); }
static retvalue checkimproveorinclude(const char *sourcedir, const char *basefilename, const char *filekey, struct checksums **checksums_p, bool *improving) { retvalue r; struct checksums *checksums = NULL; bool improves, copied = false; char *fullfilename = files_calcfullfilename(filekey); if (FAILEDTOALLOC(fullfilename)) return RET_ERROR_OOM; if (checksums_iscomplete(*checksums_p)) { r = checksums_cheaptest(fullfilename, *checksums_p, true); if (r != RET_NOTHING) { free(fullfilename); return r; } } else { r = checksums_read(fullfilename, &checksums); if (RET_WAS_ERROR(r)) { free(fullfilename); return r; } } if (r == RET_NOTHING) { char *sourcefilename = calc_dirconcat(sourcedir, basefilename); if (FAILEDTOALLOC(sourcefilename)) { free(fullfilename); return RET_ERROR_OOM; } fprintf(stderr, "WARNING: file %s was lost!\n" "(i.e. found in the database, but not in the pool)\n" "trying to compensate...\n", filekey); (void)dirs_make_parent(fullfilename); r = checksums_copyfile(fullfilename, sourcefilename, false, &checksums); if (r == RET_ERROR_EXIST) { fprintf(stderr, "File '%s' seems to be missing and existing at the same time!\n" "To confused to continue...\n", fullfilename); } if (r == RET_NOTHING) { fprintf(stderr, "Could not open '%s'!\n", sourcefilename); r = RET_ERROR_MISSING; } free(sourcefilename); if (RET_WAS_ERROR(r)) { free(fullfilename); return r; } copied = true; } assert (checksums != NULL); if (!checksums_check(*checksums_p, checksums, &improves)) { if (copied) { deletefile(fullfilename); fprintf(stderr, "ERROR: Unexpected content of file '%s/%s'!\n", sourcedir, basefilename); } else // TODO: if the database only listed some of the currently supported checksums, // and the caller of checkincludefile supplied some (which none yet does), but // not all (which needs at least three checksums, i.e. not applicaple before // sha256 get added), then this might also be called if the file in the pool // just has the same checksums as previously recorded (e.g. a md5sum collision) // but the new file was listed with another secondary hash than the original. // In that situation it might be a bit misleading... fprintf(stderr, "ERROR: file %s is damaged!\n" "(i.e. found in the database, but with different checksums in the pool)\n", filekey); checksums_printdifferences(stderr, *checksums_p, checksums); r = RET_ERROR_WRONG_MD5; } if (improves) { r = checksums_combine(checksums_p, checksums, NULL); if (RET_IS_OK(r)) *improving = true; } checksums_free(checksums); free(fullfilename); return r; }
retvalue aptmethod_enqueue(struct aptmethod *method, const char *origfile, /*@only@*/char *destfile, queue_callback *callback, void *privdata1, void *privdata2) { return enqueuenew(method, calc_dirconcat(method->baseuri, origfile), destfile, callback, privdata1, privdata2); }
inline static retvalue aptmethod_startup(struct aptmethod *method) { pid_t f; int mstdin[2]; int mstdout[2]; int r; /* When there is nothing to get, there is no reason to startup * the method. */ if (method->tobedone == NULL) { return RET_NOTHING; } /* when we are already running, we are already ready...*/ if (method->child > 0) { return RET_OK; } method->status = ams_waitforcapabilities; r = pipe(mstdin); if (r < 0) { int e = errno; fprintf(stderr, "Error %d creating pipe: %s\n", e, strerror(e)); return RET_ERRNO(e); } r = pipe(mstdout); if (r < 0) { int e = errno; (void)close(mstdin[0]); (void)close(mstdin[1]); fprintf(stderr, "Error %d in pipe syscall: %s\n", e, strerror(e)); return RET_ERRNO(e); } if (interrupted()) { (void)close(mstdin[0]);(void)close(mstdin[1]); (void)close(mstdout[0]);(void)close(mstdout[1]); return RET_ERROR_INTERRUPTED; } f = fork(); if (f < 0) { int e = errno; (void)close(mstdin[0]); (void)close(mstdin[1]); (void)close(mstdout[0]); (void)close(mstdout[1]); fprintf(stderr, "Error %d forking: %s\n", e, strerror(e)); return RET_ERRNO(e); } if (f == 0) { char *methodname; int e; /* child: */ (void)close(mstdin[1]); (void)close(mstdout[0]); if (dup2(mstdin[0], 0) < 0) { e = errno; fprintf(stderr, "Error %d while setting stdin: %s\n", e, strerror(e)); exit(255); } if (dup2(mstdout[1], 1) < 0) { e = errno; fprintf(stderr, "Error %d while setting stdout: %s\n", e, strerror(e)); exit(255); } closefrom(3); methodname = calc_dirconcat(global.methoddir, method->name); if (FAILEDTOALLOC(methodname)) exit(255); /* not really useful here, unless someone write reprepro * specific modules (which I hope noone will) */ sethookenvironment(NULL, NULL, NULL, NULL); /* actually call the method without any arguments: */ (void)execl(methodname, methodname, ENDOFARGUMENTS); e = errno; fprintf(stderr, "Error %d while executing '%s': %s\n", e, methodname, strerror(e)); exit(255); } /* the main program continues... */ method->child = f; if (verbose > 10) fprintf(stderr, "Method '%s' started as %d\n", method->baseuri, (int)f); (void)close(mstdin[0]); (void)close(mstdout[1]); markcloseonexec(mstdin[1]); markcloseonexec(mstdout[0]); method->mstdin = mstdin[1]; method->mstdout = mstdout[0]; method->inputbuffer = NULL; method->input_size = 0; method->alreadyread = 0; method->command = NULL; method->output_length = 0; method->alreadywritten = 0; return RET_OK; }
retvalue export_target(const char *relativedir, struct target *target, const struct exportmode *exportmode, struct release *release, bool onlyifmissing, bool snapshot) { retvalue r; struct filetorelease *file; const char *status; char *relfilename; char buffer[100]; const char *chunk; size_t chunk_len; struct target_cursor iterator; relfilename = calc_dirconcat(relativedir, exportmode->filename); if (FAILEDTOALLOC(relfilename)) return RET_ERROR_OOM; r = release_startfile(release, relfilename, exportmode->compressions, onlyifmissing, &file); if (RET_WAS_ERROR(r)) { free(relfilename); return r; } if (RET_IS_OK(r)) { if (release_oldexists(file)) { if (verbose > 5) printf(" replacing '%s/%s'%s\n", release_dirofdist(release), relfilename, exportdescription(exportmode, buffer, 100)); status = "change"; } else { if (verbose > 5) printf(" creating '%s/%s'%s\n", release_dirofdist(release), relfilename, exportdescription(exportmode, buffer, 100)); status = "new"; } r = target_openiterator(target, READONLY, &iterator); if (RET_WAS_ERROR(r)) { release_abortfile(file); free(relfilename); return r; } while (target_nextpackage_len(&iterator, NULL, &chunk, &chunk_len)) { if (chunk_len == 0) continue; (void)release_writedata(file, chunk, chunk_len); (void)release_writestring(file, "\n"); if (chunk[chunk_len-1] != '\n') (void)release_writestring(file, "\n"); } r = target_closeiterator(&iterator); if (RET_WAS_ERROR(r)) { release_abortfile(file); free(relfilename); return r; } r = release_finishfile(release, file); if (RET_WAS_ERROR(r)) { free(relfilename); return r; } } else { if (verbose > 9) printf(" keeping old '%s/%s'%s\n", release_dirofdist(release), relfilename, exportdescription(exportmode, buffer, 100)); status = "old"; } if (!snapshot) { int i; for (i = 0 ; i < exportmode->hooks.count ; i++) { const char *hook = exportmode->hooks.values[i]; r = callexporthook(hook, relfilename, status, release); if (RET_WAS_ERROR(r)) { free(relfilename); return r; } } } free(relfilename); return RET_OK; }
static inline retvalue morgue_name(const char *filekey, char **name_p, int *fd_p) { const char *name = dirs_basename(filekey); char *firsttry = calc_dirconcat(global.morguedir, name); int fd, en, number; retvalue r; if (FAILEDTOALLOC(firsttry)) return RET_ERROR_OOM; fd = open(firsttry, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666); if (fd >= 0) { assert (fd > 2); *name_p = firsttry; *fd_p = fd; return RET_OK; } en = errno; if (en == ENOENT) { r = dirs_make_recursive(global.morguedir); if (RET_WAS_ERROR(r)) { free(firsttry); return r; } /* try again */ fd = open(firsttry, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666); if (fd >= 0) { assert (fd > 2); *name_p = firsttry; *fd_p = fd; return RET_OK; } en = errno; } if (en != EEXIST) { fprintf(stderr, "error %d creating morgue-file %s: %s\n", en, firsttry, strerror(en)); free(firsttry); return RET_ERRNO(en); } /* file exists, try names with -number appended: */ for (number = 1 ; number < 1000 ; number++) { char *try = mprintf("%s-%d", firsttry, number); if (FAILEDTOALLOC(try)) { free(firsttry); return RET_ERROR_OOM; } fd = open(try, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666); if (fd >= 0) { assert (fd > 2); free(firsttry); *name_p = try; *fd_p = fd; return RET_OK; } free(try); } free(firsttry); fprintf(stderr, "Could not create a new file '%s' in morguedir '%s'!\n", name, global.morguedir); return RET_ERROR; }