Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}