Пример #1
0
static int
maybe_delete_conflicting(const char *origin, const char *version,
			 const char *pkg_path)
{
	int ret;
	const char *oversion;

	if (run_prepared_statement(VERSION, origin) != SQLITE_ROW)
		return (EPKG_FATAL); /* sqlite error */
	oversion = sqlite3_column_text(STMT(VERSION), 0);
	switch(pkg_version_cmp(oversion, version)) {
	case -1:
		pkg_emit_error("duplicate package origin: replacing older "
			       "version %s in repo with package %s for "
			       "origin %s", oversion, pkg_path, origin);

		if (run_prepared_statement(DELETE, origin) != SQLITE_DONE)
			return (EPKG_FATAL); /* sqlite error */

		ret = EPKG_OK;	/* conflict cleared */
		break;
	case 0:
	case 1:
		pkg_emit_error("duplicate package origin: package %s is not "
			       "newer than version %s already in repo for "
			       "origin %s", pkg_path, oversion, origin);
		ret = EPKG_END;	/* keep what is already in the repo */
		break;
	}
	return (ret);	
}
Пример #2
0
int
pkgdb_repo_remove_package(const char *origin)
{
    if (run_prepared_statement(DELETE, origin, origin) != SQLITE_DONE)
        return (EPKG_FATAL); /* sqlite error */

    return (EPKG_OK);
}
Пример #3
0
int
pkgdb_repo_cksum_exists(sqlite3 *sqlite, const char *cksum)
{
    if (run_prepared_statement(EXISTS, cksum) != SQLITE_ROW) {
        ERROR_SQLITE(sqlite);
        return (EPKG_FATAL);
    }
    if (sqlite3_column_int(STMT(EXISTS), 0) > 0) {
        return (EPKG_OK);
    }
    return (EPKG_END);
}
Пример #4
0
int
pkgdb_repo_add_package(struct pkg *pkg, const char *pkg_path,
                       sqlite3 *sqlite, const char *manifest_digest, bool forced)
{
    const char *name, *version, *origin, *comment, *desc;
    const char *arch, *maintainer, *www, *prefix, *sum, *rpath;
    int64_t			 flatsize, pkgsize;
    int64_t			 licenselogic;
    int			 ret;
    struct pkg_dep		*dep      = NULL;
    struct pkg_option	*option   = NULL;
    struct pkg_shlib	*shlib    = NULL;
    const pkg_object	*obj, *licenses, *categories, *annotations;
    pkg_iter		 it;
    int64_t			 package_id;

    pkg_get(pkg, PKG_ORIGIN, &origin, PKG_NAME, &name,
            PKG_VERSION, &version, PKG_COMMENT, &comment,
            PKG_DESC, &desc, PKG_ARCH, &arch,
            PKG_MAINTAINER, &maintainer, PKG_WWW, &www,
            PKG_PREFIX, &prefix, PKG_FLATSIZE, &flatsize,
            PKG_LICENSE_LOGIC, &licenselogic, PKG_CKSUM, &sum,
            PKG_PKGSIZE, &pkgsize, PKG_REPOPATH, &rpath,
            PKG_LICENSES, &licenses, PKG_CATEGORIES, &categories,
            PKG_ANNOTATIONS, &annotations);

try_again:
    if ((ret = run_prepared_statement(PKG, origin, name, version,
                                      comment, desc, arch, maintainer, www, prefix,
                                      pkgsize, flatsize, (int64_t)licenselogic, sum,
                                      rpath, manifest_digest)) != SQLITE_DONE) {
        if (ret == SQLITE_CONSTRAINT) {
            switch(maybe_delete_conflicting(origin,
                                            version, pkg_path, forced)) {
            case EPKG_FATAL: /* sqlite error */
                ERROR_SQLITE(sqlite);
                return (EPKG_FATAL);
                break;
            case EPKG_END: /* repo already has newer */
                return (EPKG_END);
                break;
            default: /* conflict cleared, try again */
                goto try_again;
                break;
            }
        } else {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }
    package_id = sqlite3_last_insert_rowid(sqlite);

    if (run_prepared_statement (FTS_APPEND, package_id,
                                name, version, origin) != SQLITE_DONE) {
        ERROR_SQLITE(sqlite);
        return (EPKG_FATAL);
    }

    dep = NULL;
    while (pkg_deps(pkg, &dep) == EPKG_OK) {
        if (run_prepared_statement(DEPS,
                                   pkg_dep_origin(dep),
                                   pkg_dep_name(dep),
                                   pkg_dep_version(dep),
                                   package_id) != SQLITE_DONE) {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }

    it = NULL;
    while ((obj = pkg_object_iterate(categories, &it))) {
        ret = run_prepared_statement(CAT1, pkg_object_string(obj));
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(CAT2, package_id,
                                         pkg_object_string(obj));
        if (ret != SQLITE_DONE)
        {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }

    it = NULL;
    while ((obj = pkg_object_iterate(licenses, &it))) {
        ret = run_prepared_statement(LIC1, pkg_object_string(obj));
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(LIC2, package_id,
                                         pkg_object_string(obj));
        if (ret != SQLITE_DONE) {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }
    option = NULL;
    while (pkg_options(pkg, &option) == EPKG_OK) {
        ret = run_prepared_statement(OPT1, pkg_option_opt(option));
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(OPT2, pkg_option_opt(option),
                                         pkg_option_value(option), package_id);
        if(ret != SQLITE_DONE) {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }

    shlib = NULL;
    while (pkg_shlibs_required(pkg, &shlib) == EPKG_OK) {
        const char *shlib_name = pkg_shlib_name(shlib);

        ret = run_prepared_statement(SHLIB1, shlib_name);
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(SHLIB_REQD, package_id,
                                         shlib_name);
        if (ret != SQLITE_DONE) {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }

    shlib = NULL;
    while (pkg_shlibs_provided(pkg, &shlib) == EPKG_OK) {
        const char *shlib_name = pkg_shlib_name(shlib);

        ret = run_prepared_statement(SHLIB1, shlib_name);
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(SHLIB_PROV, package_id,
                                         shlib_name);
        if (ret != SQLITE_DONE) {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }

    it = NULL;
    while ((obj = pkg_object_iterate(annotations, &it))) {
        const char *note_tag = pkg_object_key(obj);
        const char *note_val = pkg_object_string(obj);

        ret = run_prepared_statement(ANNOTATE1, note_tag);
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(ANNOTATE1, note_val);
        if (ret == SQLITE_DONE)
            ret = run_prepared_statement(ANNOTATE2, package_id,
                                         note_tag, note_val);
        if (ret != SQLITE_DONE) {
            ERROR_SQLITE(sqlite);
            return (EPKG_FATAL);
        }
    }

    return (EPKG_OK);
}
Пример #5
0
int
pkg_create_repo(char *path, bool force,
    void (progress)(struct pkg *pkg, void *data), void *data)
{
	FTS *fts = NULL;
	struct thd_data thd_data;
	int num_workers;
	size_t len;
	pthread_t *tids = NULL;

	struct pkg_dep *dep = NULL;
	struct pkg_category *category = NULL;
	struct pkg_license *license = NULL;
	struct pkg_option *option = NULL;
	struct pkg_shlib *shlib = NULL;

	sqlite3 *sqlite = NULL;

	int64_t package_id;
	char *errmsg = NULL;
	int retcode = EPKG_OK;
	int ret;

	char *repopath[2];
	char repodb[MAXPATHLEN + 1];
	char repopack[MAXPATHLEN + 1];

	struct archive *a = NULL;
	struct archive_entry *ae = NULL;

	if (!is_dir(path)) {
		pkg_emit_error("%s is not a directory", path);
		return (EPKG_FATAL);
	}

	repopath[0] = path;
	repopath[1] = NULL;

	len = sizeof(num_workers);
	if (sysctlbyname("hw.ncpu", &num_workers, &len, NULL, 0) == -1)
		num_workers = 6;

	if ((fts = fts_open(repopath, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
		pkg_emit_errno("fts_open", path);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	snprintf(repodb, sizeof(repodb), "%s/repo.sqlite", path);
	snprintf(repopack, sizeof(repopack), "%s/repo.txz", path);

	if (access(repopack, F_OK) == 0) {
		a = archive_read_new();
		archive_read_support_compression_all(a);
		archive_read_support_format_tar(a);
		ret = archive_read_open_filename(a, repopack, 4096);
		if (ret != ARCHIVE_OK) {
			/* if we can't unpack it it won't be useful for us */
			unlink(repopack);
		} else {
			while (archive_read_next_header(a, &ae) == ARCHIVE_OK) {
				if (!strcmp(archive_entry_pathname(ae),
				    "repo.sqlite")) {
					archive_entry_set_pathname(ae, repodb);
					archive_read_extract(a, ae,
					    EXTRACT_ARCHIVE_FLAGS);
					break;
				}
			}
		}
		if (a != NULL)
			archive_read_finish(a);
	}

	if ((retcode = initialize_repo(repodb, force, &sqlite)) != EPKG_OK)
		goto cleanup;

	if ((retcode = initialize_prepared_statements(sqlite)) != EPKG_OK)
		goto cleanup;

	thd_data.root_path = path;
	thd_data.max_results = num_workers;
	thd_data.num_results = 0;
	thd_data.stop = false;
	thd_data.fts = fts;
	pthread_mutex_init(&thd_data.fts_m, NULL);
	STAILQ_INIT(&thd_data.results);
	thd_data.thd_finished = 0;
	pthread_mutex_init(&thd_data.results_m, NULL);
	pthread_cond_init(&thd_data.has_result, NULL);
	pthread_cond_init(&thd_data.has_room, NULL);

	/* Launch workers */
	tids = calloc(num_workers, sizeof(pthread_t));
	for (int i = 0; i < num_workers; i++) {
		pthread_create(&tids[i], NULL, (void *)&read_pkg_file, &thd_data);
	}

	for (;;) {
		struct pkg_result *r;

		const char *name, *version, *origin, *comment, *desc;
		const char *arch, *maintainer, *www, *prefix;
		int64_t flatsize;
		lic_t licenselogic;

		pthread_mutex_lock(&thd_data.results_m);
		while ((r = STAILQ_FIRST(&thd_data.results)) == NULL) {
			if (thd_data.thd_finished == num_workers) {
				break;
			}
			pthread_cond_wait(&thd_data.has_result, &thd_data.results_m);
		}
		if (r != NULL) {
			STAILQ_REMOVE_HEAD(&thd_data.results, next);
			thd_data.num_results--;
			pthread_cond_signal(&thd_data.has_room);
		}
		pthread_mutex_unlock(&thd_data.results_m);
		if (r == NULL) {
			break;
		}

		if (r->retcode != EPKG_OK) {
			continue;
		}

		/* do not add if package if already in repodb
		   (possibly at a different pkg_path) */

		if (run_prepared_statement(EXISTS, r->cksum) != SQLITE_ROW) {
			ERROR_SQLITE(sqlite);
			goto cleanup;
		}
		if (sqlite3_column_int(STMT(EXISTS), 0) > 0) {
			continue;
		}

		if (progress != NULL)
			progress(r->pkg, data);

		pkg_get(r->pkg, PKG_ORIGIN, &origin, PKG_NAME, &name,
		    PKG_VERSION, &version, PKG_COMMENT, &comment,
		    PKG_DESC, &desc, PKG_ARCH, &arch,
		    PKG_MAINTAINER, &maintainer, PKG_WWW, &www,
		    PKG_PREFIX, &prefix, PKG_FLATSIZE, &flatsize,
		    PKG_LICENSE_LOGIC, &licenselogic);

	try_again:
		if ((ret = run_prepared_statement(PKG, origin, name, version,
		    comment, desc, arch, maintainer, www, prefix,
		    r->size, flatsize, (int64_t)licenselogic, r->cksum,
		    r->path)) != SQLITE_DONE) {
			if (ret == SQLITE_CONSTRAINT) {
				switch(maybe_delete_conflicting(origin,
				    version, r->path)) {
				case EPKG_FATAL: /* sqlite error */
					ERROR_SQLITE(sqlite);
					retcode = EPKG_FATAL;
					goto cleanup;
					break;
				case EPKG_END: /* repo already has newer */
					continue;
					break;
				default: /* conflict cleared, try again */
					goto try_again;
					break;
				}
			} else {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}

		package_id = sqlite3_last_insert_rowid(sqlite);

		dep = NULL;
		while (pkg_deps(r->pkg, &dep) == EPKG_OK) {
			if (run_prepared_statement(DEPS,
			    pkg_dep_origin(dep),
			    pkg_dep_name(dep),
			    pkg_dep_version(dep),
			    package_id) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}

		category = NULL;
		while (pkg_categories(r->pkg, &category) == EPKG_OK) {
			const char *cat_name = pkg_category_name(category);

			ret = run_prepared_statement(CAT1, cat_name);
			if (ret == SQLITE_DONE)
			    ret = run_prepared_statement(CAT2, package_id,
			        cat_name);
			if (ret != SQLITE_DONE)
			{
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}

		license = NULL;
		while (pkg_licenses(r->pkg, &license) == EPKG_OK) {
			const char *lic_name = pkg_license_name(license);

			ret = run_prepared_statement(LIC1, lic_name);
			if (ret == SQLITE_DONE)
				ret = run_prepared_statement(LIC2, package_id,
				    lic_name);
			if (ret != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}
		option = NULL;
		while (pkg_options(r->pkg, &option) == EPKG_OK) {
			if (run_prepared_statement(OPTS,
			    pkg_option_opt(option),
			    pkg_option_value(option),
			    package_id) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}

		shlib = NULL;
		while (pkg_shlibs(r->pkg, &shlib) == EPKG_OK) {
			const char *shlib_name = pkg_shlib_name(shlib);

			ret = run_prepared_statement(SHLIB1, shlib_name);
			if (ret == SQLITE_DONE)
			    ret = run_prepared_statement(SHLIB2, package_id,
			        shlib_name);
			if (ret != SQLITE_DONE)
			{
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}

		pkg_free(r->pkg);
		free(r);
	}

	if (pkgdb_transaction_commit(sqlite, NULL) != SQLITE_OK)
		retcode = EPKG_FATAL;

	cleanup:

	if (tids != NULL) {
		// Cancel running threads
		if (retcode != EPKG_OK) {
			pthread_mutex_lock(&thd_data.fts_m);
			thd_data.stop = true;
			pthread_mutex_unlock(&thd_data.fts_m);
		}
		// Join on threads to release thread IDs
		for (int i = 0; i < num_workers; i++) {
			pthread_join(tids[i], NULL);
		}
		free(tids);
	}

	if (fts != NULL)
		fts_close(fts);

	finalize_prepared_statements();

	if (sqlite != NULL)
		sqlite3_close(sqlite);

	if (errmsg != NULL)
		sqlite3_free(errmsg);

	sqlite3_shutdown();

	return (retcode);
}