int sha256_file(const char *path, char out[65]) { FILE *fp; char buffer[BUFSIZ]; unsigned char hash[SHA256_DIGEST_LENGTH]; size_t r = 0; SHA256_CTX sha256; if ((fp = fopen(path, "rb")) == NULL) return (pkg_error_set(EPKG_FATAL, "fopen(%s): %s", path, strerror(errno))); SHA256_Init(&sha256); while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) SHA256_Update(&sha256, buffer, r); if (ferror(fp) != 0) { fclose(fp); out[0] = '\0'; return (pkg_error_set(EPKG_FATAL, "fread(%s): %s", path, strerror(errno))); } fclose(fp); SHA256_Final(hash, &sha256); sha256_hash(hash, out); return (EPKG_OK); }
int pkg_fetch_buffer(const char *url, char **buffer, void *data, fetch_cb cb) { FILE *remote = NULL; struct url_stat st; off_t done = 0; off_t r; int retry = 3; time_t begin_dl; time_t now; time_t last = 0; int retcode = EPKG_OK; while (remote == NULL) { remote = fetchXGetURL(url, &st, ""); if (remote == NULL) { --retry; if (retry == 0) { pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString); goto cleanup; } sleep(1); } } *buffer = malloc(st.size + 1); begin_dl = time(NULL); while (done < st.size) { if ((r = fread(*buffer + done, 1, 10240, remote)) < 1) break; done += r; now = time(NULL); /* Only call the callback every second */ if (cb != NULL && (now > last || done == st.size)) { cb(data, url, st.size, done, (now - begin_dl)); last = now; } } if (ferror(remote)) { retcode = pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString); goto cleanup; } cleanup: if (remote != NULL) fclose(remote); return (retcode); }
/* Based off src/bin/mkdir/mkdir.c 1.32 */ int pkg_dir_build(const char *path) { struct stat sb; int last, retval; char *str, *p; str = strdup(path); if (!str) { pkg_error_set(&pkg_null, "Out of Memory"); return PKG_FAIL; } p = str; retval = PKG_OK; if (p[0] == '/') /* Skip leading '/'. */ ++p; for (last = 0; !last ; ++p) { if (p[0] == '\0') last = 1; else if (p[0] != '/') continue; *p = '\0'; if (!last && p[1] == '\0') last = 1; if (mkdir(str, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { if (errno == EEXIST || errno == EISDIR) { if (stat(str, &sb) < 0) { retval = PKG_FAIL; pkg_error_set(&pkg_null, "Could not stat %s", str); break; } else if (!S_ISDIR(sb.st_mode)) { if (last) errno = EEXIST; else errno = ENOTDIR; retval = PKG_FAIL; pkg_error_set(&pkg_null, "%s is not a directory", str); break; } } else { retval = PKG_FAIL; pkg_error_set(&pkg_null, "Could not create %s", str); break; } } if (!last) *p = '/'; } free(str); return (retval); }
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); }
int pkg_delete(struct pkg *pkg, struct pkgdb *db, int force) { struct pkg **rdeps; int i, ret; struct sbuf *rdep_msg; if (pkg == NULL) return (ERROR_BAD_ARG("pkg")); if (db == NULL) return (ERROR_BAD_ARG("db")); /* * Ensure that we have all the informations we need */ if ((ret = pkgdb_loadrdeps(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_loadfiles(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_loadscripts(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_loadmtree(db, pkg)) != EPKG_OK) return (ret); rdeps = pkg_rdeps(pkg); if (rdeps[0] != NULL) { rdep_msg = sbuf_new_auto(); sbuf_printf(rdep_msg, "%s-%s is required by other packages:", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION)); for (i = 0;rdeps[i] != NULL; i++) { sbuf_cat(rdep_msg, " "); sbuf_printf(rdep_msg, "%s-%s", pkg_get(rdeps[i], PKG_NAME), pkg_get(rdeps[i], PKG_VERSION)); } if (!force) { sbuf_finish(rdep_msg); ret = pkg_error_set(EPKG_REQUIRED, "%s", sbuf_get(rdep_msg)); sbuf_free(rdep_msg); return ret; } sbuf_cat(rdep_msg, ", deleting anyway"); sbuf_finish(rdep_msg); fprintf(stderr, "%s\n", sbuf_get(rdep_msg)); sbuf_free(rdep_msg); } if ((ret = pkg_script_pre_deinstall(pkg)) != EPKG_OK) return (ret); if ((ret = pkg_delete_files(pkg, force)) != EPKG_OK) return (ret); if ((ret = pkg_script_post_deinstall(pkg)) != EPKG_OK) return (ret); return (pkgdb_unregister_pkg(db, pkg_get(pkg, PKG_ORIGIN))); }
int file_to_buffer(const char *path, char **buffer, off_t *sz) { int fd; struct stat st; if (path == NULL || path[0] == '\0') return (ERROR_BAD_ARG("path")); if (buffer == NULL) return (ERROR_BAD_ARG("buffer")); if ((fd = open(path, O_RDONLY)) == -1) { return (pkg_error_set(EPKG_FATAL, "can not open %s: %s", path, strerror(errno))); } if (fstat(fd, &st) == -1) { close(fd); return (pkg_error_set(EPKG_FATAL, "fstat(): %s", strerror(errno))); } if ((*buffer = malloc(st.st_size + 1)) == NULL) { close(fd); return (pkg_error_set(EPKG_FATAL, "malloc(): %s", strerror(errno))); } if (read(fd, *buffer, st.st_size) == -1) { close(fd); return (pkg_error_set(EPKG_FATAL, "read(): %s", strerror(errno))); } close(fd); /* NULL terminate the buffer so it can be used by stdio.h functions */ (*buffer)[st.st_size] = '\0'; *sz = st.st_size; return (EPKG_OK); }
int pkgdb_register_finale(struct pkgdb *db, int retcode) { int ret = EPKG_OK; const char *commands[] = { "COMMIT;", "ROLLBACK;", NULL }; const char *command; char *errmsg; if (!pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) { ret = pkg_error_set(EPKG_FATAL, "database command not in flight"); return ret; } command = (retcode == EPKG_OK) ? commands[0] : commands[1]; if (sqlite3_exec(db->sqlite, command, NULL, NULL, &errmsg) != SQLITE_OK) { ret = pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg); sqlite3_free(errmsg); } PKGDB_UNSET_FLAG(db, PKGDB_FLAG_IN_FLIGHT); return ret; }
/* Checks a file against a given md5 checksum */ int pkg_checksum_md5(struct pkg_file *file, char *chk_sum) { char sum[33]; if (!file) { pkg_error_set(&pkg_null, "No file specified"); return PKG_FAIL; } if (!sum) { pkg_error_set((struct pkg_object *)file, "No checksum specified"); return PKG_FAIL; } /* Perform a checksum on the file to install */ MD5Data(file->contents, file->len, sum); if (strcmp(sum, chk_sum)) { pkg_error_set((struct pkg_object *)file, "File checksum incorrect"); return PKG_FAIL; } return PKG_OK; }
static struct pkgdb_it * pkgdb_it_new(struct pkgdb *db, sqlite3_stmt *s, int type) { struct pkgdb_it *it; if ((it = malloc(sizeof(struct pkgdb_it))) == NULL) { pkg_error_set(EPKG_FATAL, "malloc(): %s", strerror(errno)); sqlite3_finalize(s); return (NULL); } it->db = db; it->stmt = s; it->type = type; return (it); }
int pkg_create_installed(const char *outdir, pkg_formats format, const char *rootdir, struct pkg *pkg) { struct packing *pkg_archive; int required_flags = PKG_LOAD_DEPS | PKG_LOAD_CONFLICTS | PKG_LOAD_FILES | PKG_LOAD_SCRIPTS | PKG_LOAD_OPTIONS | PKG_LOAD_MTREE; if (pkg->type != PKG_INSTALLED) return (ERROR_BAD_ARG("pkg")); pkg_archive = pkg_create_archive(outdir, pkg, format, required_flags); if (pkg_archive == NULL) return pkg_error_set(EPKG_FATAL, "unable to create archive"); /* XXX do better */ pkg_create_from_dir(pkg, rootdir, pkg_archive); return packing_finish(pkg_archive); }
int pkg_fetch_file(const char *url, const char *dest, void *data, fetch_cb cb) { int fd = -1; FILE *remote = NULL; struct url_stat st; off_t done = 0; off_t r; int retry = 3; time_t begin_dl; time_t now; time_t last = 0; char buf[10240]; int retcode = EPKG_OK; if ((fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { retcode = pkg_error_set(EPKG_FATAL, "open(%s): %s", dest, strerror(errno)); goto cleanup; } while (remote == NULL) { remote = fetchXGetURL(url, &st, ""); if (remote == NULL) { --retry; if (retry == 0) { retcode = pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString); goto cleanup; } sleep(1); } } begin_dl = time(NULL); while (done < st.size) { if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) break; if (write(fd, buf, r) != r) { retcode = pkg_error_set(EPKG_FATAL, "write(%s): %s", dest, strerror(errno)); goto cleanup; } done += r; now = time(NULL); /* Only call the callback every second */ if (cb != NULL && (now > last || done == st.size)) { cb(data, url, st.size, done, (now - begin_dl)); last = now; } } if (ferror(remote)) { retcode = pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString); goto cleanup; } cleanup: if (fd > 0) close(fd); if (remote != NULL) fclose(remote); /* Remove local file if fetch failed */ if (retcode != EPKG_OK) unlink(dest); return (retcode); }
int pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg) { struct pkg **deps; struct pkg_file **files; struct pkg_conflict **conflicts; struct pkg_script **scripts; struct pkg_option **options; sqlite3 *s; sqlite3_stmt *stmt_pkg = NULL; sqlite3_stmt *stmt_sel_pkg = NULL; sqlite3_stmt *stmt_dep = NULL; sqlite3_stmt *stmt_conflict = NULL; sqlite3_stmt *stmt_file = NULL; sqlite3_stmt *stmt_script = NULL; sqlite3_stmt *stmt_option = NULL; sqlite3_stmt *stmt_dirs = NULL; int i; int ret; int retcode = EPKG_OK; const char *path; int64_t package_id; char *errmsg; const char sql_begin[] = "BEGIN TRANSACTION;"; const char sql_pkg[] = "" "INSERT INTO pkg_mtree( " "origin, name, version, comment, desc, mtree, message, arch, " "osversion, maintainer, www, prefix, flatsize) " "VALUES( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13);"; const char sql_sel_pkg[] = "" "SELECT id FROM packages " "WHERE origin = ?1;"; const char sql_dep[] = "" "INSERT INTO deps (origin, name, version, package_id) " "VALUES (?1, ?2, ?3, ?4);"; const char sql_conflict[] = "" "INSERT INTO conflicts (name, package_id) " "VALUES (?1, ?2);"; const char sql_file[] = "" "INSERT INTO files (path, sha256, package_id) " "VALUES (?1, ?2, ?3);"; const char sql_script[] = "" "INSERT INTO scripts (script, type, package_id) " "VALUES (?1, ?2, ?3);"; const char sql_option[] = "" "INSERT INTO options (option, value, package_id) " "VALUES (?1, ?2, ?3);"; const char sql_dir[] = "" "INSERT INTO pkg_dirs(origin, path) " "VALUES (?1, ?2);"; if (pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) { pkg_error_set(EPKG_FATAL, "tried to register a package with an in-flight SQL command"); return (EPKG_FATAL); } s = db->sqlite; if (sqlite3_exec(s, sql_begin, NULL, NULL, &errmsg) != SQLITE_OK) { pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg); sqlite3_free(errmsg); return (EPKG_FATAL); } PKGDB_SET_FLAG(db, PKGDB_FLAG_IN_FLIGHT); /* * Insert package record */ if (sqlite3_prepare_v2(s, sql_pkg, -1, &stmt_pkg, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_bind_text(stmt_pkg, 1, pkg_get(pkg, PKG_ORIGIN), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 2, pkg_get(pkg, PKG_NAME), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 3, pkg_get(pkg, PKG_VERSION), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 4, pkg_get(pkg, PKG_COMMENT), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 5, pkg_get(pkg, PKG_DESC), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 6, pkg_get(pkg, PKG_MTREE), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 7, pkg_get(pkg, PKG_MESSAGE), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 8, pkg_get(pkg, PKG_ARCH), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 9, pkg_get(pkg, PKG_OSVERSION), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 10, pkg_get(pkg, PKG_MAINTAINER), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 11, pkg_get(pkg, PKG_WWW), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_pkg, 12, pkg_get(pkg, PKG_PREFIX), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt_pkg, 13, pkg_flatsize(pkg)); if ((ret = sqlite3_step(stmt_pkg)) != SQLITE_DONE) { if ( ret == SQLITE_CONSTRAINT) retcode = pkg_error_set(EPKG_FATAL, "constraint violation on " "pkg with %s", pkg_get(pkg, PKG_ORIGIN)); else retcode = ERROR_SQLITE(s); goto cleanup; } /* * Get the generated package_id */ if (sqlite3_prepare_v2(s, sql_sel_pkg, -1, &stmt_sel_pkg, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_bind_text(stmt_sel_pkg, 1, pkg_get(pkg, PKG_ORIGIN), -1, SQLITE_STATIC); ret = sqlite3_step(stmt_sel_pkg); if (ret == SQLITE_ROW) { package_id = sqlite3_column_int64(stmt_sel_pkg, 0); ret = SQLITE_DONE; } else { retcode = ERROR_SQLITE(s); goto cleanup; } /* * Insert dependencies list */ if (sqlite3_prepare_v2(s, sql_dep, -1, &stmt_dep, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } deps = pkg_deps(pkg); for (i = 0; deps[i] != NULL; i++) { sqlite3_bind_text(stmt_dep, 1, pkg_get(deps[i], PKG_ORIGIN), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_dep, 2, pkg_get(deps[i], PKG_NAME), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_dep, 3, pkg_get(deps[i], PKG_VERSION), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt_dep, 4, package_id); if ((ret = sqlite3_step(stmt_dep)) != SQLITE_DONE) { if ( ret == SQLITE_CONSTRAINT) retcode = pkg_error_set(EPKG_FATAL, "constraint violation on " "deps with %s", pkg_get(deps[i], PKG_ORIGIN)); else retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_reset(stmt_dep); } /* * Insert conflicts list */ if (sqlite3_prepare_v2(s, sql_conflict, -1, &stmt_conflict, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } conflicts = pkg_conflicts(pkg); for (i = 0; conflicts[i] != NULL; i++) { sqlite3_bind_text(stmt_conflict, 1, pkg_conflict_glob(conflicts[i]), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt_conflict, 2, package_id); if ((ret = sqlite3_step(stmt_conflict)) != SQLITE_DONE) { if ( ret == SQLITE_CONSTRAINT) retcode = pkg_error_set(EPKG_FATAL, "constraint violation on " "conflicts with %s", pkg_conflict_glob(conflicts[i])); else retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_reset(stmt_conflict); } /* * Insert file * and dirs */ if (sqlite3_prepare_v2(s, sql_file, -1, &stmt_file, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } if (sqlite3_prepare_v2(s, sql_dir, -1, &stmt_dirs, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } files = pkg_files(pkg); for (i = 0; files[i] != NULL; i++) { path = pkg_file_path(files[i]); if (path[strlen(path) - 1 ] != '/') { sqlite3_bind_text(stmt_file, 1, pkg_file_path(files[i]), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_file, 2, pkg_file_sha256(files[i]), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt_file, 3, package_id); if ((ret = sqlite3_step(stmt_file)) != SQLITE_DONE) { if ( ret == SQLITE_CONSTRAINT) retcode = pkg_error_set(EPKG_FATAL, "constraint violation on " "path with %s", pkg_file_path(files[i])); else retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_reset(stmt_file); } else { sqlite3_bind_text(stmt_dirs, 1, pkg_get(pkg, PKG_ORIGIN), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_dirs, 2, pkg_file_path(files[i]), -1, SQLITE_STATIC); if ((ret = sqlite3_step(stmt_dirs)) != SQLITE_DONE) { if ( ret == SQLITE_CONSTRAINT) retcode = pkg_error_set(EPKG_FATAL, "constraint violation on " "dirs with %s", pkg_file_path(files[i])); else retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_reset(stmt_dirs); } } /* * Insert scripts */ if (sqlite3_prepare_v2(s, sql_script, -1, &stmt_script, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } scripts = pkg_scripts(pkg); for (i = 0; scripts[i] != NULL; i++) { sqlite3_bind_text(stmt_script, 1, pkg_script_data(scripts[i]), -1, SQLITE_STATIC); sqlite3_bind_int(stmt_script, 2, pkg_script_type(scripts[i])); sqlite3_bind_int64(stmt_script, 3, package_id); if (sqlite3_step(stmt_script) != SQLITE_DONE) { if ( ret == SQLITE_CONSTRAINT) retcode = pkg_error_set(EPKG_FATAL, "constraint violation on " "scripts with %s", pkg_script_data(scripts[i])); else retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_reset(stmt_script); } /* * Insert options */ options = pkg_options(pkg); if (sqlite3_prepare_v2(s, sql_option, -1, &stmt_option, NULL) != SQLITE_OK) { retcode = ERROR_SQLITE(s); goto cleanup; } for (i = 0; options[i] != NULL; i++) { sqlite3_bind_text(stmt_option, 1, pkg_option_opt(options[i]), -1, SQLITE_STATIC); sqlite3_bind_text(stmt_option, 2, pkg_option_value(options[i]), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt_option, 3, package_id); if (sqlite3_step(stmt_option) != SQLITE_DONE) { retcode = ERROR_SQLITE(s); goto cleanup; } sqlite3_reset(stmt_option); } cleanup: if (stmt_pkg != NULL) sqlite3_finalize(stmt_pkg); if (stmt_sel_pkg != NULL) sqlite3_finalize(stmt_sel_pkg); if (stmt_dep != NULL) sqlite3_finalize(stmt_dep); if (stmt_conflict != NULL) sqlite3_finalize(stmt_conflict); if (stmt_file != NULL) sqlite3_finalize(stmt_file); if (stmt_script != NULL) sqlite3_finalize(stmt_script); if (stmt_option != NULL) sqlite3_finalize(stmt_option); if (stmt_dirs != NULL) sqlite3_finalize(stmt_dirs); return (retcode); }
int pkgdb_open(struct pkgdb **db, pkgdb_t remote, int mode) { int retcode; struct stat st; char *errmsg; char localpath[MAXPATHLEN]; char remotepath[MAXPATHLEN]; char sql[BUFSIZ]; const char *dbdir; /* First check to make sure PKG_DBDIR exists before trying to use it */ dbdir = pkg_config("PKG_DBDIR"); if (eaccess(dbdir, mode) == -1) return (pkg_error_set(EPKG_FATAL, "Package database directory " "%s error: %s", dbdir, strerror(errno))); snprintf(localpath, sizeof(localpath), "%s/local.sqlite", dbdir); if ((*db = calloc(1, sizeof(struct pkgdb))) == NULL) return (pkg_error_set(EPKG_FATAL, "calloc(): %s", strerror(errno))); (*db)->remote = remote; retcode = stat(localpath, &st); if (retcode == -1 && errno != ENOENT) return (pkg_error_set(EPKG_FATAL, "can not stat %s: %s", localpath, strerror(errno))); if (remote == PKGDB_REMOTE) { snprintf(remotepath, sizeof(localpath), "%s/repo.sqlite", dbdir); retcode = stat(remotepath, &st); if (retcode == -1 && errno != ENOENT) return (pkg_error_set(EPKG_FATAL, "can not stat %s: %s", remotepath, strerror(errno))); } if (sqlite3_open(localpath, &(*db)->sqlite) != SQLITE_OK) return (ERROR_SQLITE((*db)->sqlite)); if (remote == PKGDB_REMOTE) { sqlite3_snprintf(BUFSIZ, sql, "ATTACH \"%s\" as remote;", remotepath); if (sqlite3_exec((*db)->sqlite, sql, NULL, NULL, &errmsg) != SQLITE_OK){ sqlite3_free(errmsg); return ERROR_SQLITE((*db)->sqlite); } } /* If the database is missing we have to initialize it */ if (retcode == -1) if ((retcode = pkgdb_init((*db)->sqlite)) != EPKG_OK) return (ERROR_SQLITE((*db)->sqlite)); sqlite3_create_function((*db)->sqlite, "regexp", 2, SQLITE_ANY, NULL, pkgdb_regex_basic, NULL, NULL); sqlite3_create_function((*db)->sqlite, "eregexp", 2, SQLITE_ANY, NULL, pkgdb_regex_extended, NULL, NULL); sqlite3_create_function((*db)->sqlite, "pkglt", 2, SQLITE_ANY, NULL, pkgdb_pkglt, NULL, NULL); sqlite3_create_function((*db)->sqlite, "pkggt", 2, SQLITE_ANY, NULL, pkgdb_pkggt, NULL, NULL); /* * allow forign key option which will allow to have clean support for * reinstalling */ if (sqlite3_exec((*db)->sqlite, "PRAGMA foreign_keys = ON;", NULL, NULL, &errmsg) != SQLITE_OK) { pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg); sqlite3_free(errmsg); return (EPKG_FATAL); } return (EPKG_OK); }
static int pkgdb_init(sqlite3 *sdb) { char *errmsg; const char sql[] = "" "CREATE TABLE packages (" "id INTEGER PRIMARY KEY," "origin TEXT UNIQUE," "name TEXT," "version TEXT," "comment TEXT," "desc TEXT," "mtree_id INTEGER REFERENCES mtree(id) ON DELETE RESTRICT" " ON UPDATE CASCADE," "message TEXT," "arch TEXT," "osversion TEXT," "maintainer TEXT," "www TEXT," "prefix TEXT," "flatsize INTEGER," "automatic INTEGER," "pkg_format_version INTEGER" ");" "CREATE TABLE mtree (" "id INTEGER PRIMARY KEY," "content TEXT UNIQUE" ");" "CREATE TRIGGER clean_mtree AFTER DELETE ON packages BEGIN " "DELETE FROM mtree WHERE id NOT IN (SELECT DISTINCT mtree_id FROM packages);" "END;" "CREATE VIEW pkg_mtree AS " "SELECT origin, name, version, comment, desc, mtree.content AS mtree, message, arch, osversion, " "maintainer, www, prefix, flatsize, automatic, pkg_format_version FROM packages " "INNER JOIN mtree ON packages.mtree_id = mtree.id;" "CREATE TRIGGER pkg_insert INSTEAD OF INSERT ON pkg_mtree " "FOR EACH ROW BEGIN " "INSERT OR IGNORE INTO mtree (content) VALUES (NEW.mtree);" "INSERT OR REPLACE INTO packages(origin, name, version, comment, desc, mtree_id, " "message, arch, osversion, maintainer, www, prefix, flatsize) " "VALUES (NEW.origin, NEW.name, NEW.version, NEW.comment, NEW.desc, " "(SELECT id FROM mtree WHERE content = NEW.mtree), " "NEW.message, NEW.arch, NEW.osversion, NEW.maintainer, NEW.www, NEW.prefix, " "NEW.flatsize);" "END;" "CREATE TABLE scripts (" "package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE" " ON UPDATE CASCADE," "script TEXT," "type INTEGER," "PRIMARY KEY (package_id, type)" ");" "CREATE INDEX scripts_package ON scripts(package_id);" "CREATE TABLE options (" "package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE" " ON UPDATE CASCADE," "option TEXT," "value TEXT," "PRIMARY KEY (package_id,option)" ");" "CREATE INDEX options_package ON options(package_id);" "CREATE TABLE deps (" "origin TEXT," "name TEXT," "version TEXT," "package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE" " ON UPDATE CASCADE," "PRIMARY KEY (package_id,origin)" ");" "CREATE INDEX deps_origin ON deps(origin);" "CREATE INDEX deps_package ON deps(package_id);" "CREATE TABLE files (" "path TEXT PRIMARY KEY," "sha256 TEXT," "package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE" " ON UPDATE CASCADE" ");" "CREATE INDEX files_package ON files(package_id);" "CREATE TABLE conflicts (" "name TEXT," "package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE" " ON UPDATE CASCADE," "PRIMARY KEY (package_id,name)" ");" "CREATE INDEX conflicts_package ON conflicts(package_id);" "CREATE TABLE directories (" "id INTEGER PRIMARY KEY, " "path TEXT " ");" "CREATE TABLE pkg_dirs_assoc (" "package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE" " ON UPDATE CASCADE, " "directory_id INTEGER REFERENCES directories(id) ON DELETE RESTRICT" " ON UPDATE RESTRICT, " "PRIMARY KEY (package_id, directory_id)" ");" "CREATE VIEW pkg_dirs AS SELECT origin, path FROM packages " "INNER JOIN pkg_dirs_assoc ON packages.id = pkg_dirs_assoc.package_id " "INNER JOIN directories ON pkg_dirs_assoc.directory_id = directories.id;" "CREATE TRIGGER pkg_dirs_clean AFTER DELETE ON packages BEGIN " "DELETE from directories WHERE id NOT IN (SELECT DISTINCT directory_id FROM pkg_dirs_assoc);" "END;" "CREATE TRIGGER dir_insert INSTEAD OF INSERT ON pkg_dirs " "FOR EACH ROW BEGIN " "INSERT OR IGNORE INTO directories (path) VALUES (NEW.path);" "INSERT INTO pkg_dirs_assoc (package_id, directory_id) VALUES " "((SELECT id FROM packages WHERE origin = NEW.origin), " "(SELECT id FROM directories WHERE path = NEW.path));" "END;" ; if (sqlite3_exec(sdb, sql, NULL, NULL, &errmsg) != SQLITE_OK) { pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg); sqlite3_free(errmsg); return (EPKG_FATAL); } return (EPKG_OK); }