int pkgdb_compact(struct pkgdb *db) { int64_t page_count = 0; int64_t freelist_count = 0; char *errmsg; int retcode = EPKG_OK; if (db == NULL) return (ERROR_BAD_ARG("db")); if (get_pragma(db->sqlite, "PRAGMA page_count;", &page_count) != EPKG_OK) return (EPKG_FATAL); if (get_pragma(db->sqlite, "PRAGMA freelist_count;", &freelist_count) != EPKG_OK) return (EPKG_FATAL); /* * Only compact if we will save 25% (or more) of the current used space. */ if (freelist_count / (float)page_count < 0.25) return (EPKG_OK); if (sqlite3_exec(db->sqlite, "VACUUM;", NULL, NULL, &errmsg) != SQLITE_OK){ retcode = pkg_error_set(EPKG_FATAL, "%s", errmsg); sqlite3_free(errmsg); } return (retcode); }
grn_query * grn_query_open(grn_ctx *ctx, const char *str, unsigned int str_len, grn_operator default_op, int max_exprs) { grn_query *q; int max_cells = max_exprs * 4; if (!(q = GRN_MALLOC(sizeof(grn_query) + max_cells * sizeof(grn_cell) + str_len + 1))) { GRN_LOG(ctx, GRN_LOG_ALERT, "grn_query_open malloc fail"); return NULL; } q->header.type = GRN_QUERY; q->str = (char *)&q->cell_pool[max_cells]; memcpy(q->str, str, str_len); q->str[str_len] = '\0'; q->cur = q->str; q->str_end = q->str + str_len; q->default_op = default_op; q->encoding = ctx->encoding; q->max_exprs = max_exprs; q->max_cells = max_cells; q->cur_cell = 0; q->cur_expr = 0; q->escalation_threshold = GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD; q->escalation_decaystep = DEFAULT_DECAYSTEP; q->weight_offset = 0; q->opt.weight_vector = NULL; q->weight_set = NULL; get_pragma(ctx, q); q->expr = get_expr(ctx, q); q->opt.vector_size = DEFAULT_WEIGHT_VECTOR_SIZE; q->opt.func = q->weight_set ? section_weight_cb : NULL; q->opt.func_arg = q->weight_set; q->snip_conds = NULL; return q; }
int pkg_update(const char *name, const char *packagesite, bool force) { char url[MAXPATHLEN]; struct archive *a = NULL; struct archive_entry *ae = NULL; char repofile[MAXPATHLEN]; char repofile_unchecked[MAXPATHLEN]; char tmp[MAXPATHLEN]; const char *dbdir = NULL; const char *repokey; unsigned char *sig = NULL; int siglen = 0; int fd, rc = EPKG_FATAL, ret; struct stat st; time_t t = 0; sqlite3 *sqlite; char *archreq = NULL; const char *myarch; int64_t res; const char *tmpdir; snprintf(url, MAXPATHLEN, "%s/repo.txz", packagesite); tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; strlcpy(tmp, tmpdir, sizeof(tmp)); strlcat(tmp, "/repo.txz.XXXXXX", sizeof(tmp)); fd = mkstemp(tmp); if (fd == -1) { pkg_emit_error("Could not create temporary file %s, " "aborting update.\n", tmp); return (EPKG_FATAL); } if (pkg_config_string(PKG_CONFIG_DBDIR, &dbdir) != EPKG_OK) { pkg_emit_error("Cant get dbdir config entry"); return (EPKG_FATAL); } snprintf(repofile, sizeof(repofile), "%s/%s.sqlite", dbdir, name); if (force) t = 0; /* Always fetch */ else { if (stat(repofile, &st) != -1) { t = st.st_mtime; /* add 1 minute to the timestamp because * repo.sqlite is always newer than repo.txz, * 1 minute should be enough. */ t += 60; } } rc = pkg_fetch_file_to_fd(url, fd, t); close(fd); if (rc != EPKG_OK) { goto cleanup; } if (eaccess(repofile, W_OK) == -1) { pkg_emit_error("Insufficient privilege to update %s\n", repofile); rc = EPKG_ENOACCESS; goto cleanup; } a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_tar(a); archive_read_open_filename(a, tmp, 4096); while (archive_read_next_header(a, &ae) == ARCHIVE_OK) { if (strcmp(archive_entry_pathname(ae), "repo.sqlite") == 0) { snprintf(repofile_unchecked, sizeof(repofile_unchecked), "%s.unchecked", repofile); archive_entry_set_pathname(ae, repofile_unchecked); /* * The repo should be owned by root and not writable */ archive_entry_set_uid(ae, 0); archive_entry_set_gid(ae, 0); archive_entry_set_perm(ae, 0644); archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS); } if (strcmp(archive_entry_pathname(ae), "signature") == 0) { siglen = archive_entry_size(ae); sig = malloc(siglen); archive_read_data(a, sig, siglen); } } if (pkg_config_string(PKG_CONFIG_REPOKEY, &repokey) != EPKG_OK) { free(sig); return (EPKG_FATAL); } if (repokey != NULL) { if (sig != NULL) { ret = rsa_verify(repofile_unchecked, repokey, sig, siglen - 1); if (ret != EPKG_OK) { pkg_emit_error("Invalid signature, " "removing repository.\n"); unlink(repofile_unchecked); free(sig); rc = EPKG_FATAL; goto cleanup; } free(sig); } else { pkg_emit_error("No signature found in the repository. " "Can not validate against %s key.", repokey); rc = EPKG_FATAL; unlink(repofile_unchecked); goto cleanup; } } /* check is the repository is for valid architecture */ sqlite3_initialize(); if (sqlite3_open(repofile_unchecked, &sqlite) != SQLITE_OK) { unlink(repofile_unchecked); pkg_emit_error("Corrupted repository"); rc = EPKG_FATAL; goto cleanup; } pkg_config_string(PKG_CONFIG_ABI, &myarch); archreq = sqlite3_mprintf("select count(arch) from packages " "where arch not GLOB '%q'", myarch); if (get_pragma(sqlite, archreq, &res) != EPKG_OK) { sqlite3_free(archreq); pkg_emit_error("Unable to query repository"); rc = EPKG_FATAL; sqlite3_close(sqlite); goto cleanup; } if (res > 0) { pkg_emit_error("At least one of the packages provided by" "the repository is not compatible with your abi: %s", myarch); rc = EPKG_FATAL; sqlite3_close(sqlite); goto cleanup; } sqlite3_close(sqlite); sqlite3_shutdown(); if (rename(repofile_unchecked, repofile) != 0) { pkg_emit_errno("rename", ""); rc = EPKG_FATAL; goto cleanup; } if ((rc = remote_add_indexes(name)) != EPKG_OK) goto cleanup; rc = EPKG_OK; cleanup: if (a != NULL) archive_read_finish(a); (void)unlink(tmp); return (rc); }
int pkg_update(struct pkg_repo *repo, bool force) { char repofile[MAXPATHLEN]; const char *dbdir = NULL; struct stat st; time_t t = 0; sqlite3 *sqlite = NULL; char *req = NULL; int64_t res; sqlite3_initialize(); if (pkg_config_string(PKG_CONFIG_DBDIR, &dbdir) != EPKG_OK) { pkg_emit_error("Cant get dbdir config entry"); return (EPKG_FATAL); } snprintf(repofile, sizeof(repofile), "%s/%s.sqlite", dbdir, pkg_repo_name(repo)); if (stat(repofile, &st) != -1) t = force ? 0 : st.st_mtime; if (t != 0) { if (sqlite3_open(repofile, &sqlite) != SQLITE_OK) { pkg_emit_error("Unable to open local database"); return (EPKG_FATAL); } if (get_pragma(sqlite, "SELECT count(name) FROM sqlite_master " "WHERE type='table' AND name='repodata';", &res) != EPKG_OK) { pkg_emit_error("Unable to query repository"); sqlite3_close(sqlite); return (EPKG_FATAL); } if (res != 1) { t = 0; if (sqlite != NULL) { sqlite3_close(sqlite); sqlite = NULL; } } } if (t != 0) { req = sqlite3_mprintf("select count(key) from repodata " "WHERE key = \"packagesite\" and value = '%q'", pkg_repo_url(repo)); if (get_pragma(sqlite, req, &res) != EPKG_OK) { sqlite3_free(req); pkg_emit_error("Unable to query repository"); sqlite3_close(sqlite); return (EPKG_FATAL); } sqlite3_free(req); if (res != 1) { t = 0; if (sqlite != NULL) { sqlite3_close(sqlite); sqlite = NULL; } unlink(repofile); } } res = pkg_update_incremental(repofile, repo, &t); if (res != EPKG_OK && res != EPKG_UPTODATE) { pkg_emit_notice("No digest falling back on legacy catalog format"); /* Still try to do full upgrade */ if ((res = pkg_update_full(repofile, repo, &t)) != EPKG_OK) goto cleanup; } res = EPKG_OK; cleanup: /* Set mtime from http request if possible */ if (t != 0) { struct timeval ftimes[2] = { { .tv_sec = t, .tv_usec = 0 }, { .tv_sec = t, .tv_usec = 0 } };
int pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode) { char filepath[MAXPATHLEN]; struct statfs stfs; const char *dbdir = NULL; sqlite3 *sqlite = NULL; int flags; int64_t res; struct pkg_repo_it *it; struct pkg *pkg = NULL; const char *digest; sqlite3_initialize(); dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR")); /* * Fall back on unix-dotfile locking strategy if on a network filesystem */ if (statfs(dbdir, &stfs) == 0) { if ((stfs.f_flags & MNT_LOCAL) != MNT_LOCAL) sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1); } snprintf(filepath, sizeof(filepath), "%s/%s.meta", dbdir, pkg_repo_name(repo)); /* Open metafile */ if (access(filepath, R_OK) != -1) { if (pkg_repo_meta_load(filepath, &repo->meta) != EPKG_OK) return (EPKG_FATAL); } snprintf(filepath, sizeof(filepath), "%s/%s", dbdir, pkg_repo_binary_get_filename(pkg_repo_name(repo))); /* Always want read mode here */ if (access(filepath, R_OK | mode) != 0) return (EPKG_ENOACCESS); flags = (mode & W_OK) != 0 ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; if (sqlite3_open_v2(filepath, &sqlite, flags, NULL) != SQLITE_OK) return (EPKG_FATAL); /* Sanitise sqlite database */ if (get_pragma(sqlite, "SELECT count(name) FROM sqlite_master " "WHERE type='table' AND name='repodata';", &res, false) != EPKG_OK) { pkg_emit_error("Unable to query repository"); sqlite3_close(sqlite); return (EPKG_FATAL); } if (res != 1) { pkg_emit_notice("Repository %s contains no repodata table, " "need to re-create database", repo->name); sqlite3_close(sqlite); return (EPKG_FATAL); } /* Check package site */ char *req = sqlite3_mprintf("select count(key) from repodata " "WHERE key = \"packagesite\" and value = '%q'", pkg_repo_url(repo)); res = 0; get_pragma(sqlite, req, &res, true); sqlite3_free(req); if (res != 1) { pkg_emit_notice("Repository %s has a wrong packagesite, need to " "re-create database", repo->name); sqlite3_close(sqlite); return (EPKG_FATAL); } /* Check version */ if (pkg_repo_binary_check_version(repo, sqlite) != EPKG_OK) { pkg_emit_error("need to re-create repo %s to upgrade schema version", repo->name); sqlite3_close(sqlite); if (mode & W_OK) unlink(filepath); return (EPKG_REPOSCHEMA); } repo->priv = sqlite; /* Check digests format */ if ((it = pkg_repo_binary_query(repo, NULL, MATCH_ALL)) == NULL) return (EPKG_OK); if (it->ops->next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) { it->ops->free(it); return (EPKG_OK); } it->ops->free(it); pkg_get(pkg, PKG_DIGEST, &digest); if (digest == NULL || !pkg_checksum_is_valid(digest, strlen(digest))) { pkg_emit_notice("Repository %s has incompatible checksum format, need to " "re-create database", repo->name); pkg_free(pkg); sqlite3_close(sqlite); repo->priv = NULL; return (EPKG_FATAL); } pkg_free(pkg); return (EPKG_OK); }