static int pkg_repo_binary_init_update(struct pkg_repo *repo, const char *name) { sqlite3 *sqlite; const char update_check_sql[] = "" "INSERT INTO repo_update VALUES(1);"; const char update_start_sql[] = "" "CREATE TABLE IF NOT EXISTS repo_update (n INT);"; /* [Re]create repo */ unlink(name); if (repo->ops->create(repo) != EPKG_OK) { pkg_emit_notice("Unable to create repository %s", repo->name); return (EPKG_FATAL); } if (repo->ops->open(repo, R_OK|W_OK) != EPKG_OK) { pkg_emit_notice("Unable to open created repository %s", repo->name); return (EPKG_FATAL); } repo->ops->init(repo); sqlite = PRIV_GET(repo); if(sqlite3_exec(sqlite, update_check_sql, NULL, NULL, NULL) == SQLITE_OK) { pkg_emit_notice("Previous update has not been finished, restart it"); return (EPKG_END); } else { sql_exec(sqlite, update_start_sql); } return (EPKG_OK); }
int pkg_repo_binary_init(struct pkg_repo *repo) { int retcode = EPKG_OK; sqlite3 *sqlite = PRIV_GET(repo); sqlite3_create_function(sqlite, "file_exists", 2, SQLITE_ANY, NULL, sqlite_file_exists, NULL, NULL); retcode = sql_exec(sqlite, "PRAGMA synchronous=default"); if (retcode != EPKG_OK) return (retcode); retcode = sql_exec(sqlite, "PRAGMA foreign_keys=on"); if (retcode != EPKG_OK) return (retcode); pkgdb_sqlcmd_init(sqlite, NULL, NULL); retcode = pkg_repo_binary_init_prstatements(sqlite); if (retcode != EPKG_OK) return (retcode); repo->priv = sqlite; return (EPKG_OK); }
static struct pkg_repo_it* pkg_repo_binary_it_new(struct pkg_repo *repo, sqlite3_stmt *s, short flags) { struct pkg_repo_it *it; struct pkgdb fakedb; it = malloc(sizeof(*it)); if (it == NULL) { pkg_emit_errno("malloc", "pkg_repo_it"); sqlite3_finalize(s); return (NULL); } it->ops = &pkg_repo_binary_it_ops; it->flags = flags; it->repo = repo; fakedb.sqlite = PRIV_GET(repo); it->data = pkgdb_it_new_sqlite(&fakedb, s, PKG_REMOTE, flags); if (it->data == NULL) { free(it); return (NULL); } return (it); }
struct pkg_repo_it * pkg_repo_binary_require(struct pkg_repo *repo, const char *provide) { sqlite3_stmt *stmt; sqlite3 *sqlite = PRIV_GET(repo); UT_string *sql = NULL; int ret; const char basesql[] = "" "SELECT p.id, p.origin, p.name, p.version, p.comment, " "p.name as uniqueid, " "p.prefix, p.desc, p.arch, p.maintainer, p.www, " "p.licenselogic, p.flatsize, p.pkgsize, " "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname " "FROM packages AS p INNER JOIN pkg_requires AS ps ON " "p.id = ps.package_id " "WHERE ps.require_id = (SELECT id FROM requires WHERE require=?1);"; utstring_new(sql); utstring_printf(sql, basesql, repo->name); pkg_debug(4, "Pkgdb: running '%s'", utstring_body(sql)); ret = sqlite3_prepare_v2(sqlite, utstring_body(sql), -1, &stmt, NULL); if (ret != SQLITE_OK) { ERROR_SQLITE(sqlite, utstring_body(sql)); utstring_free(sql); return (NULL); } utstring_free(sql); sqlite3_bind_text(stmt, 1, provide, -1, SQLITE_TRANSIENT); return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE)); }
int64_t pkg_repo_binary_stat(struct pkg_repo *repo, pkg_stats_t type) { sqlite3 *sqlite = PRIV_GET(repo); sqlite3_stmt *stmt = NULL; int64_t stats = 0; struct sbuf *sql = NULL; int ret; sql = sbuf_new_auto(); switch(type) { case PKG_STATS_LOCAL_COUNT: goto out; break; case PKG_STATS_LOCAL_SIZE: goto out; break; case PKG_STATS_REMOTE_UNIQUE: sbuf_printf(sql, "SELECT COUNT(id) FROM main.packages;"); break; case PKG_STATS_REMOTE_COUNT: sbuf_printf(sql, "SELECT COUNT(id) FROM main.packages;"); break; case PKG_STATS_REMOTE_SIZE: sbuf_printf(sql, "SELECT SUM(pkgsize) FROM main.packages;"); break; case PKG_STATS_REMOTE_REPOS: goto out; break; } sbuf_finish(sql); pkg_debug(4, "binary_repo: running '%s'", sbuf_data(sql)); ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL); if (ret != SQLITE_OK) { ERROR_SQLITE(sqlite, sbuf_data(sql)); goto out; } while (sqlite3_step(stmt) != SQLITE_DONE) { stats = sqlite3_column_int64(stmt, 0); } out: sbuf_free(sql); if (stmt != NULL) sqlite3_finalize(stmt); return (stats); }
struct pkg_repo_it * pkg_repo_binary_query(struct pkg_repo *repo, const char *pattern, match_t match) { sqlite3 *sqlite = PRIV_GET(repo); sqlite3_stmt *stmt = NULL; struct sbuf *sql = NULL; const char *comp = NULL; int ret; char basesql[BUFSIZ] = "" "SELECT id, origin, name, name as uniqueid, version, comment, " "prefix, desc, arch, maintainer, www, " "licenselogic, flatsize, pkgsize, " "cksum, manifestdigest, path AS repopath, '%s' AS dbname " "FROM packages AS p"; if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0')) return (NULL); sql = sbuf_new_auto(); comp = pkgdb_get_pattern_query(pattern, match); if (comp && comp[0]) strlcat(basesql, comp, sizeof(basesql)); sbuf_printf(sql, basesql, repo->name); sbuf_cat(sql, " ORDER BY name;"); sbuf_finish(sql); pkg_debug(4, "Pkgdb: running '%s' query for %s", sbuf_data(sql), pattern == NULL ? "all": pattern); ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), sbuf_len(sql), &stmt, NULL); if (ret != SQLITE_OK) { ERROR_SQLITE(sqlite, sbuf_data(sql)); sbuf_delete(sql); return (NULL); } sbuf_delete(sql); if (match != MATCH_ALL && match != MATCH_CONDITION) sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT); return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE)); }
int pkg_repo_binary_ensure_loaded(struct pkg_repo *repo, struct pkg *pkg, unsigned flags) { sqlite3 *sqlite = PRIV_GET(repo); struct pkg_manifest_key *keys = NULL; struct pkg *cached = NULL; char path[MAXPATHLEN]; if (pkg->type != PKG_INSTALLED && (flags & (PKG_LOAD_FILES|PKG_LOAD_DIRS)) != 0 && (pkg->flags & (PKG_LOAD_FILES|PKG_LOAD_DIRS)) == 0) { /* * Try to get that information from fetched package in cache */ pkg_manifest_keys_new(&keys); if (pkg_repo_cached_name(pkg, path, sizeof(path)) != EPKG_OK) return (EPKG_FATAL); pkg_debug(1, "Binary> loading %s", path); if (pkg_open(&cached, path, keys, PKG_OPEN_TRY) != EPKG_OK) { pkg_free(cached); return (EPKG_FATAL); } /* Now move required elements to the provided package */ pkg_list_free(pkg, PKG_FILES); pkg_list_free(pkg, PKG_DIRS); pkg->files = cached->files; pkg->filehash = cached->filehash; pkg->dirs = cached->dirs; pkg->dirhash = cached->dirhash; cached->files = NULL; cached->filehash = NULL; cached->dirs = NULL; cached->dirhash = NULL; pkg_free(cached); pkg->flags |= (PKG_LOAD_FILES|PKG_LOAD_DIRS); } return (pkgdb_ensure_loaded_sqlite(sqlite, pkg, flags)); }
struct pkg_repo_it * pkg_repo_binary_search(struct pkg_repo *repo, const char *pattern, match_t match, pkgdb_field field, pkgdb_field sort) { sqlite3 *sqlite = PRIV_GET(repo); sqlite3_stmt *stmt = NULL; struct sbuf *sql = NULL; int ret; const char *multireposql = "" "SELECT id, origin, name, version, comment, " "prefix, desc, arch, maintainer, www, " "licenselogic, flatsize, pkgsize, " "cksum, path AS repopath, '%1$s' AS dbname, '%2$s' AS repourl " "FROM packages "; if (pattern == NULL || pattern[0] == '\0') return (NULL); sql = sbuf_new_auto(); sbuf_printf(sql, multireposql, repo->name, repo->url); /* close the UNIONs and build the search query */ sbuf_cat(sql, "WHERE "); pkg_repo_binary_build_search_query(sql, match, field, sort); sbuf_cat(sql, ";"); sbuf_finish(sql); pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql)); ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL); if (ret != SQLITE_OK) { ERROR_SQLITE(sqlite, sbuf_data(sql)); sbuf_delete(sql); return (NULL); } sbuf_delete(sql); sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_TRANSIENT); return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE)); }
int pkg_repo_binary_close(struct pkg_repo *repo, bool commit) { int retcode = EPKG_OK; sqlite3 *sqlite = PRIV_GET(repo); if (sqlite == NULL) return (retcode); if (commit) { if (pkgdb_transaction_commit(sqlite, NULL) != SQLITE_OK) retcode = EPKG_FATAL; } pkg_repo_binary_finalize_prstatements(); sqlite3_free(sqlite); repo->priv = NULL; return (retcode); }
struct pkg_repo_it * pkg_repo_binary_shlib_provide(struct pkg_repo *repo, const char *require) { sqlite3_stmt *stmt; sqlite3 *sqlite = PRIV_GET(repo); struct sbuf *sql = NULL; int ret; const char basesql[] = "" "SELECT p.id, p.origin, p.name, p.version, p.comment, " "p.name as uniqueid, " "p.prefix, p.desc, p.arch, p.maintainer, p.www, " "p.licenselogic, p.flatsize, p.pkgsize, " "p.cksum, p.manifestdigest, p.path AS repopath, '%s' AS dbname " "FROM packages AS p INNER JOIN pkg_shlibs_provided AS ps ON " "p.id = ps.package_id " "WHERE ps.shlib_id IN (SELECT id FROM shlibs WHERE " "name BETWEEN ?1 AND ?1 || '.9');"; sql = sbuf_new_auto(); sbuf_printf(sql, basesql, repo->name); sbuf_finish(sql); pkg_debug(4, "Pkgdb: running '%s'", sbuf_data(sql)); ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL); if (ret != SQLITE_OK) { ERROR_SQLITE(sqlite, sbuf_data(sql)); sbuf_delete(sql); return (NULL); } sbuf_delete(sql); sqlite3_bind_text(stmt, 1, require, -1, SQLITE_TRANSIENT); return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE)); }
static int pkg_repo_binary_update_incremental(const char *name, struct pkg_repo *repo, time_t *mtime, bool force) { FILE *fmanifest = NULL, *fdigests = NULL /*, *fconflicts = NULL*/; struct pkg *pkg = NULL; int rc = EPKG_FATAL; sqlite3 *sqlite = NULL; sqlite3_stmt *stmt; const char *origin, *digest, *offset, *length, *checksum; char *linebuf = NULL, *p; int updated = 0, removed = 0, added = 0, processed = 0, pushed = 0; long num_offset, num_length; time_t local_t; time_t digest_t; time_t packagesite_t; struct pkg_increment_task_item *ldel = NULL, *ladd = NULL, *item, *tmp_item; struct pkg_manifest_key *keys = NULL; size_t linecap = 0; ssize_t linelen; char *map = MAP_FAILED; size_t len = 0; int hash_it = 0; bool in_trans = false, legacy_repo = false; /* Required for making iterator */ struct pkgdb_it *it = NULL; struct pkgdb fakedb; pkg_debug(1, "Pkgrepo, begin incremental update of '%s'", name); /* In forced mode, ignore mtime */ if (force) *mtime = 0; /* Fetch meta */ local_t = *mtime; if (pkg_repo_fetch_meta(repo, &local_t) == EPKG_FATAL) pkg_emit_notice("repository %s has no meta file, using " "default settings", repo->name); /* Fetch digests */ local_t = *mtime; fdigests = pkg_repo_fetch_remote_extract_tmp(repo, repo->meta->digests, &local_t, &rc); if (fdigests == NULL) goto cleanup; /* Fetch packagesite */ digest_t = local_t; local_t = *mtime; fmanifest = pkg_repo_fetch_remote_extract_tmp(repo, repo->meta->manifests, &local_t, &rc); if (fmanifest == NULL) goto cleanup; packagesite_t = local_t; *mtime = digest_t; /*fconflicts = repo_fetch_remote_extract_tmp(repo, repo_conflicts_archive, "txz", &local_t, &rc, repo_conflicts_file);*/ fseek(fmanifest, 0, SEEK_END); len = ftell(fmanifest); /* Detect whether we have legacy repo */ if ((linelen = getline(&linebuf, &linecap, fdigests)) > 0) { p = linebuf; origin = strsep(&p, ":"); digest = strsep(&p, ":"); if (digest == NULL) { pkg_emit_error("invalid digest file format"); rc = EPKG_FATAL; goto cleanup; } if (!pkg_checksum_is_valid(digest, strlen(digest))) { legacy_repo = true; pkg_debug(1, "repository '%s' has a legacy digests format", repo->name); } } fseek(fdigests, 0, SEEK_SET); /* Load local repository data */ rc = pkg_repo_binary_init_update(repo, name, force); if (rc == EPKG_END) { /* Need to perform forced update */ repo->ops->close(repo, false); return (pkg_repo_binary_update_incremental(name, repo, mtime, true)); } if (rc != EPKG_OK) { rc = EPKG_FATAL; goto cleanup; } /* Here sqlite is initialized */ sqlite = PRIV_GET(repo); stmt = pkg_repo_binary_get_origins(sqlite); if (stmt == NULL) { rc = EPKG_FATAL; goto cleanup; } fakedb.sqlite = sqlite; it = pkgdb_it_new_sqlite(&fakedb, stmt, PKG_REMOTE, PKGDB_IT_FLAG_ONCE); if (it != NULL) { while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) { pkg_get(pkg, PKG_ORIGIN, &origin, legacy_repo ? PKG_OLD_DIGEST : PKG_DIGEST, &digest, PKG_CKSUM, &checksum); pkg_repo_binary_update_item_new(&ldel, origin, digest, 0, 0, checksum); } pkgdb_it_free(it); } else { sqlite3_finalize(stmt); } pkg_debug(1, "Pkgrepo, reading new packagesite.yaml for '%s'", name); /* load the while digests */ while ((linelen = getline(&linebuf, &linecap, fdigests)) > 0) { p = linebuf; origin = strsep(&p, ":"); digest = strsep(&p, ":"); offset = strsep(&p, ":"); /* files offset */ strsep(&p, ":"); length = p ? strsep(&p, ":\n") : NULL; checksum = p ? strsep(&p, ":\n") : NULL; if (origin == NULL || digest == NULL || offset == NULL) { pkg_emit_error("invalid digest file format"); rc = EPKG_FATAL; goto cleanup; } errno = 0; num_offset = (long)strtoul(offset, NULL, 10); if (errno != 0) { pkg_emit_errno("strtoul", "digest format error"); rc = EPKG_FATAL; goto cleanup; } if (length != NULL) { errno = 0; num_length = (long)strtoul(length, NULL, 10); if (errno != 0) { pkg_emit_errno("strtoul", "digest format error"); rc = EPKG_FATAL; goto cleanup; } } else { num_length = 0; } processed++; HASH_FIND_STR(ldel, origin, item); if (item == NULL) { added++; pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset, num_length, checksum); } else { HASH_DEL(ldel, item); if (checksum == NULL || item->checksum == NULL) { pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset, num_length, checksum); updated++; } else if (strcmp(checksum, item->checksum) != 0) { /* Allow checksum to be used as unique mark */ pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset, num_length, checksum); updated++; } pkg_repo_binary_update_item_free(item); } } rc = EPKG_OK; pkg_debug(1, "Pkgrepo, removing old entries for '%s'", name); rc = pkgdb_transaction_begin(sqlite, "REPO"); if (rc != EPKG_OK) goto cleanup; in_trans = true; removed = HASH_COUNT(ldel); hash_it = 0; if (removed > 0) pkg_emit_progress_start("Removing expired repository entries"); HASH_ITER(hh, ldel, item, tmp_item) { pkg_emit_progress_tick(++hash_it, removed); if (rc == EPKG_OK) { rc = pkgdb_repo_remove_package(item->origin); } else { pkg_emit_progress_tick(removed, removed); } HASH_DEL(ldel, item); pkg_repo_binary_update_item_free(item); }