Newer
Older
/* database.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/file.h>
#include "apk_defines.h"
#include "apk_package.h"
#include "apk_database.h"
#include "apk_state.h"
const char * const apkindex_tar_gz = "APKINDEX.tar.gz";
const char * const apk_index_gz = "APK_INDEX.gz";
static const char * const apk_static_cache_dir = "var/lib/apk";
static const char * const apk_linked_cache_dir = "etc/apk/cache";
struct install_ctx {
struct apk_database *db;
struct apk_package *pkg;
int script;
apk_progress_cb cb;
void *cb_ctx;
size_t installed_size;
size_t current_file_size;
struct hlist_node **diri_node;
struct hlist_node **file_diri_node;
};
static apk_blob_t pkg_name_get_key(apk_hash_item item)
{
return APK_BLOB_STR(((struct apk_name *) item)->name);
}
static void pkg_name_free(struct apk_name *name)
{
free(name->name);
free(name->pkgs);
free(name);
}
static const struct apk_hash_ops pkg_name_hash_ops = {
.node_offset = offsetof(struct apk_name, hash_node),
.get_key = pkg_name_get_key,
.hash_key = apk_blob_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) pkg_name_free,
};
static apk_blob_t pkg_info_get_key(apk_hash_item item)
{
return APK_BLOB_CSUM(((struct apk_package *) item)->csum);
}
static unsigned long csum_hash(apk_blob_t csum)
{
/* Checksum's highest bits have the most "randomness", use that
* directly as hash */
}
static const struct apk_hash_ops pkg_info_hash_ops = {
.node_offset = offsetof(struct apk_package, hash_node),
.get_key = pkg_info_get_key,
.hash_key = csum_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) apk_pkg_free,
};
static apk_blob_t apk_db_dir_get_key(apk_hash_item item)
{
struct apk_db_dir *dir = (struct apk_db_dir *) item;
return APK_BLOB_PTR_LEN(dir->name, dir->namelen);
}
static const struct apk_hash_ops dir_hash_ops = {
.node_offset = offsetof(struct apk_db_dir, hash_node),
.get_key = apk_db_dir_get_key,
.hash_key = apk_blob_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) free,
};
struct apk_db_file_hash_key {
apk_blob_t dirname;
apk_blob_t filename;
};
static unsigned long apk_db_file_hash_key(apk_blob_t _key)
struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
return apk_blob_hash_seed(key->filename, apk_blob_hash(key->dirname));
}
static unsigned long apk_db_file_hash_item(apk_hash_item item)
{
struct apk_db_file *dbf = (struct apk_db_file *) item;
return apk_blob_hash_seed(APK_BLOB_PTR_LEN(dbf->name, dbf->namelen),
dbf->diri->dir->hash);
}
static int apk_db_file_compare_item(apk_hash_item item, apk_blob_t _key)
{
struct apk_db_file *dbf = (struct apk_db_file *) item;
struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
int r;
r = apk_blob_compare(key->filename,
APK_BLOB_PTR_LEN(dbf->name, dbf->namelen));
if (r != 0)
return r;
r = apk_blob_compare(key->dirname,
APK_BLOB_PTR_LEN(dir->name, dir->namelen));
return r;
}
static const struct apk_hash_ops file_hash_ops = {
.node_offset = offsetof(struct apk_db_file, hash_node),
.hash_key = apk_db_file_hash_key,
.hash_item = apk_db_file_hash_item,
.compare_item = apk_db_file_compare_item,
.delete_item = (apk_hash_delete_f) free,
};
struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name)
{
return (struct apk_name *) apk_hash_get(&db->available.names, name);
}
struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name)
{
struct apk_name *pn;
unsigned long hash = apk_hash_from_key(&db->available.names, name);
pn = (struct apk_name *) apk_hash_get_hashed(&db->available.names, name, hash);
if (pn != NULL)
return pn;
pn = calloc(1, sizeof(struct apk_name));
if (pn == NULL)
return NULL;
apk_hash_insert_hashed(&db->available.names, pn, hash);
return pn;
}
static void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir)
{
dir->refs--;
if (dir->refs > 0)
return;
db->installed.stats.dirs--;
if (dir->parent != NULL)
apk_db_dir_unref(db, dir->parent);
}
static struct apk_db_dir *apk_db_dir_ref(struct apk_db_dir *dir)
{
dir->refs++;
return dir;
}
struct apk_db_dir *apk_db_dir_query(struct apk_database *db,
apk_blob_t name)
{
return (struct apk_db_dir *) apk_hash_get(&db->installed.dirs, name);
}
static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
apk_blob_t name)
{
struct apk_db_dir *dir;
apk_blob_t bparent;
unsigned long hash = apk_hash_from_key(&db->installed.dirs, name);
if (name.len && name.ptr[name.len-1] == '/')
name.len--;
dir = (struct apk_db_dir *) apk_hash_get_hashed(&db->installed.dirs, name, hash);
if (dir != NULL)
return apk_db_dir_ref(dir);
dir = malloc(sizeof(*dir) + name.len + 1);
memset(dir, 0, sizeof(*dir));
memcpy(dir->name, name.ptr, name.len);
dir->name[name.len] = 0;
dir->namelen = name.len;
dir->hash = hash;
apk_hash_insert_hashed(&db->installed.dirs, dir, hash);
if (name.len == 0)
dir->parent = NULL;
else if (apk_blob_rsplit(name, '/', &bparent, NULL))
dir->parent = apk_db_dir_get(db, bparent);
dir->parent = apk_db_dir_get(db, APK_BLOB_NULL);
if (dir->parent != NULL)
dir->flags = dir->parent->flags;
for (i = 0; i < db->protected_paths->num; i++) {
if (db->protected_paths->item[i][0] == '-' &&
strcmp(&db->protected_paths->item[i][1], dir->name) == 0)
dir->flags &= ~APK_DBDIRF_PROTECTED;
else if (strcmp(db->protected_paths->item[i], dir->name) == 0)
dir->flags |= APK_DBDIRF_PROTECTED;
}
return dir;
}
static struct apk_db_dir_instance *apk_db_diri_new(struct apk_database *db,
struct apk_package *pkg,
apk_blob_t name,
struct hlist_node ***after)
{
struct apk_db_dir_instance *diri;
diri = calloc(1, sizeof(struct apk_db_dir_instance));
hlist_add_after(&diri->pkg_dirs_list, *after);
*after = &diri->pkg_dirs_list.next;
diri->dir = apk_db_dir_get(db, name);
return diri;
}
static void apk_db_diri_set(struct apk_db_dir_instance *diri, mode_t mode,
uid_t uid, gid_t gid)
{
diri->mode = mode;
diri->uid = uid;
diri->gid = gid;
}
static void apk_db_diri_mkdir(struct apk_db_dir_instance *diri)
if (mkdir(diri->dir->name, diri->mode) == 0)
chown(diri->dir->name, diri->uid, diri->gid);
static void apk_db_diri_rmdir(struct apk_db_dir_instance *diri)
{
if (diri->dir->refs == 1)
rmdir(diri->dir->name);
static void apk_db_diri_free(struct apk_database *db,
struct apk_db_dir_instance *diri)
{
apk_db_dir_unref(db, diri->dir);
struct apk_db_file *apk_db_file_query(struct apk_database *db,
apk_blob_t dir,
apk_blob_t name)
{
struct apk_db_file_hash_key key;
key = (struct apk_db_file_hash_key) {
.dirname = dir,
.filename = name,
};
return (struct apk_db_file *) apk_hash_get(&db->installed.files,
APK_BLOB_BUF(&key));
}
static struct apk_db_file *apk_db_file_get(struct apk_database *db,
struct apk_db_dir_instance *diri,
apk_blob_t name,
struct hlist_node ***after)
{
struct apk_db_file *file;
struct apk_db_file_hash_key key;
struct apk_db_dir *dir = diri->dir;
unsigned long hash;
key = (struct apk_db_file_hash_key) {
.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
.filename = name,
};
hash = apk_blob_hash_seed(name, dir->hash);
file = (struct apk_db_file *) apk_hash_get_hashed(
&db->installed.files, APK_BLOB_BUF(&key), hash);
if (file != NULL)
return file;
file = malloc(sizeof(*file) + name.len + 1);
memset(file, 0, sizeof(*file));
memcpy(file->name, name.ptr, name.len);
file->name[name.len] = 0;
file->namelen = name.len;
file->diri = diri;
hlist_add_after(&file->diri_files_list, *after);
*after = &file->diri_files_list.next;
apk_hash_insert_hashed(&db->installed.files, file, hash);
db->installed.stats.files++;
return file;
}
static void apk_db_file_change_owner(struct apk_database *db,
struct apk_db_file *file,
struct apk_db_dir_instance *diri,
struct hlist_node ***after)
{
hlist_del(&file->diri_files_list, &file->diri->owned_files);
hlist_add_after(&file->diri_files_list, *after);
*after = &file->diri_files_list.next;
}
static void apk_db_pkg_rdepends(struct apk_database *db, struct apk_package *pkg)
{
int i, j;
if (pkg->depends == NULL)
return;
for (i = 0; i < pkg->depends->num; i++) {
struct apk_name *rname = pkg->depends->item[i].name;
if (rname->rdepends) {
for (j = 0; j < rname->rdepends->num; j++)
if (rname->rdepends->item[j] == pkg->name)
return;
}
*apk_name_array_add(&rname->rdepends) = pkg->name;
}
}
struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg)
idb = apk_hash_get(&db->available.packages, APK_BLOB_CSUM(pkg->csum));
if (idb == NULL) {
idb = pkg;
apk_hash_insert(&db->available.packages, pkg);
*apk_package_array_add(&pkg->name->pkgs) = pkg;
if (idb->filename == NULL && pkg->filename != NULL) {
idb->filename = pkg->filename;
pkg->filename = NULL;
}
apk_pkg_free(pkg);
}
return idb;
}
int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
{
struct apk_package *pkg = NULL;
struct apk_db_dir_instance *diri = NULL;
struct apk_db_file *file = NULL;
struct hlist_node **diri_node = NULL;
struct hlist_node **file_diri_node = NULL;
apk_blob_t token = APK_BLOB_STR("\n"), l;
int field;
while (!APK_BLOB_IS_NULL(l = bs->read(bs, token))) {
if (l.len < 2 || l.ptr[1] != ':') {
if (pkg == NULL)
continue;
if (repo != -1)
pkg->repos |= BIT(repo);
else
apk_pkg_set_state(db, pkg, APK_PKG_INSTALLED);
if (apk_db_pkg_add(db, pkg) != pkg && repo == -1) {
apk_error("Installed database load failed");
return -1;
pkg = NULL;
continue;
}
/* Get field */
field = l.ptr[0];
l.ptr += 2;
l.len -= 2;
/* If no package, create new */
if (pkg == NULL) {
pkg = apk_pkg_new();
diri = NULL;
diri_node = hlist_tail_ptr(&pkg->owned_dirs);
file_diri_node = NULL;
}
/* Standard index line? */
if (apk_pkg_add_info(db, pkg, field, l) == 0)
continue;
if (repo != -1) {
apk_error("Invalid index entry '%c'", field);
return -1;
}
/* Check FDB special entries */
switch (field) {
case 'F':
if (pkg->name == NULL) {
apk_error("FDB directory entry before package entry");
diri = apk_db_diri_new(db, pkg, l, &diri_node);
file_diri_node = &diri->owned_files.first;
break;
case 'M':
if (diri == NULL) {
apk_error("FDB directory metadata entry before directory entry");
return -1;
}
diri->uid = apk_blob_pull_uint(&l, 10);
apk_blob_pull_char(&l, ':');
diri->gid = apk_blob_pull_uint(&l, 10);
apk_blob_pull_char(&l, ':');
diri->mode = apk_blob_pull_uint(&l, 8);
break;
case 'R':
if (diri == NULL) {
apk_error("FDB file entry before directory entry");
return -1;
}
file = apk_db_file_get(db, diri, l,
&file_diri_node);
break;
case 'Z':
if (file == NULL) {
apk_error("FDB checksum entry before file entry");
return -1;
}
break;
default:
apk_error("FDB entry '%c' unsupported", field);
return -1;
}
if (APK_BLOB_IS_NULL(l)) {
apk_error("FDB format error in entry '%c'", field);
return -1;
}
}
}
static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
{
struct apk_package *pkg;
struct apk_db_file *file;
char buf[1024];
apk_blob_t bbuf = APK_BLOB_BUF(buf);
int r;
list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) {
r = apk_pkg_write_index_entry(pkg, os);
if (r < 0)
return r;
hlist_for_each_entry(diri, c1, &pkg->owned_dirs, pkg_dirs_list) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:"));
apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen));
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nM:"));
apk_blob_push_uint(&bbuf, diri->uid, 10);
apk_blob_push_blob(&bbuf, APK_BLOB_STR(":"));
apk_blob_push_uint(&bbuf, diri->gid, 10);
apk_blob_push_blob(&bbuf, APK_BLOB_STR(":"));
apk_blob_push_uint(&bbuf, diri->mode, 8);
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
hlist_for_each_entry(file, c2, &diri->owned_files, diri_files_list) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("R:"));
apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(file->name, file->namelen));
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nZ:"));
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
if (os->write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
if (os->write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
}
}
return 0;
}
static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os)
{
struct apk_package *pkg;
struct apk_script *script;
struct apk_file_info fi;
char filename[256];
apk_blob_t bfn;
list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) {
hlist_for_each_entry(script, c2, &pkg->scripts, script_list) {
fi = (struct apk_file_info) {
.name = filename,
.size = script->size,
.mode = 0755 | S_IFREG,
};
/* The scripts db expects file names in format:
* pkg-version.<hexdump of package checksum>.action */
bfn = APK_BLOB_BUF(filename);
apk_blob_push_blob(&bfn, APK_BLOB_STR(pkg->name->name));
apk_blob_push_blob(&bfn, APK_BLOB_STR("-"));
apk_blob_push_blob(&bfn, APK_BLOB_STR(pkg->version));
apk_blob_push_blob(&bfn, APK_BLOB_STR("."));
apk_blob_push_csum(&bfn, &pkg->csum);
apk_blob_push_blob(&bfn, APK_BLOB_STR("."));
apk_blob_push_blob(&bfn, APK_BLOB_STR(apk_script_types[script->type]));
apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1));
r = apk_tar_write_entry(os, &fi, script->script);
}
}
return apk_tar_write_entry(os, NULL, NULL);
}
static int apk_db_scriptdb_read_v1(struct apk_database *db, struct apk_istream *is)
{
struct apk_package *pkg;
struct {
unsigned char md5sum[16];
unsigned int type;
unsigned int size;
} hdr;
struct apk_checksum csum;
while (is->read(is, &hdr, sizeof(hdr)) == sizeof(hdr)) {
memcpy(csum.data, hdr.md5sum, sizeof(hdr.md5sum));
csum.type = APK_CHECKSUM_MD5;
pkg = apk_db_get_pkg(db, &csum);
if (pkg != NULL)
apk_pkg_add_script(pkg, is, hdr.type, hdr.size);
}
return 0;
}
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
static int apk_read_script_archive_entry(void *ctx,
const struct apk_file_info *ae,
struct apk_istream *is)
{
struct apk_database *db = (struct apk_database *) ctx;
struct apk_package *pkg;
char *fncsum, *fnaction;
struct apk_checksum csum;
apk_blob_t blob;
int type;
if (!S_ISREG(ae->mode))
return 0;
/* The scripts db expects file names in format:
* pkgname-version.<hexdump of package checksum>.action */
fnaction = memrchr(ae->name, '.', strlen(ae->name));
if (fnaction == NULL || fnaction == ae->name)
return 0;
fncsum = memrchr(ae->name, '.', fnaction - ae->name - 1);
if (fncsum == NULL)
return 0;
fnaction++;
fncsum++;
/* Parse it */
type = apk_script_type(fnaction);
if (type == APK_SCRIPT_INVALID)
return 0;
blob = APK_BLOB_PTR_PTR(fncsum, fnaction - 2);
apk_blob_pull_csum(&blob, &csum);
/* Attach script */
pkg = apk_db_get_pkg(db, &csum);
if (pkg != NULL)
apk_pkg_add_script(pkg, is, type, ae->size);
return 0;
}
static int apk_db_read_state(struct apk_database *db, int flags)
{
struct apk_bstream *bs;
/* Read:
* 1. installed repository
* 2. source repositories
* 3. master dependencies
* 4. package statuses
* 5. files db
* 6. script db
*/
fchdir(db->root_fd);
if (!(flags & APK_OPENF_NO_WORLD)) {
blob = apk_blob_from_file("var/lib/apk/world");
if (APK_BLOB_IS_NULL(blob))
return -ENOENT;
apk_deps_parse(db, &db->world, blob);
free(blob.ptr);
for (i = 0; i < db->world->num; i++)
db->world->item[i].name->flags |= APK_NAME_TOPLEVEL;
}
bs = apk_bstream_from_file("var/lib/apk/installed");
if (bs != NULL) {
apk_db_index_read(db, bs, -1);
bs->close(bs, NULL);
}
is = apk_istream_from_file("var/lib/apk/scripts.tar");
apk_tar_parse(is, apk_read_script_archive_entry, db);
} else {
is = apk_istream_from_file("var/lib/apk/scripts");
if (is != NULL)
apk_db_scriptdb_read_v1(db, is);
}
return 0;
}
static int add_protected_path(void *ctx, apk_blob_t blob)
{
struct apk_database *db = (struct apk_database *) ctx;
*apk_string_array_add(&db->protected_paths) = apk_blob_cstr(blob);
return 0;
}
static int apk_db_create(struct apk_database *db)
{
apk_blob_t deps = APK_BLOB_STR("busybox alpine-baselayout "
"apk-tools alpine-conf");
int fd;
fchdir(db->root_fd);
mkdir("tmp", 01777);
mkdir("dev", 0755);
mknod("dev/null", 0666, makedev(1, 3));
mkdir("var", 0755);
mkdir("var/lib", 0755);
mkdir("var/lib/apk", 0755);
fd = creat("var/lib/apk/world", 0644);
if (fd < 0)
return -errno;
write(fd, deps.ptr, deps.len);
close(fd);
return 0;
}
static void handle_alarm(int sig)
{
}
int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
const char *apk_repos = getenv("APK_REPOS"), *msg = NULL;
struct apk_repository_url *repo = NULL;
struct stat st;
apk_blob_t blob;
int r;
memset(db, 0, sizeof(*db));
apk_hash_init(&db->available.names, &pkg_name_hash_ops, 1000);
apk_hash_init(&db->available.packages, &pkg_info_hash_ops, 4000);
apk_hash_init(&db->installed.dirs, &dir_hash_ops, 1000);
apk_hash_init(&db->installed.files, &file_hash_ops, 4000);
fchdir(apk_cwd_fd);
db->root = strdup(root);
db->root_fd = open(root, O_RDONLY);
if (db->root_fd < 0 && (flags & APK_OPENF_CREATE)) {
mkdir(db->root, 0755);
db->root_fd = open(root, O_RDONLY);
}
msg = "Unable to open root";
goto ret_errno;
}
fchdir(db->root_fd);
if (stat(apk_linked_cache_dir, &st) == 0 && S_ISDIR(st.st_mode))
db->cache_dir = apk_linked_cache_dir;
if (flags & APK_OPENF_WRITE) {
db->lock_fd = open("var/lib/apk/lock",
O_CREAT | O_WRONLY, 0400);
if (db->lock_fd < 0 && errno == ENOENT &&
(flags & APK_OPENF_CREATE)) {
r = apk_db_create(db);
if (r != 0) {
msg = "Unable to create database";
goto ret_r;
}
db->lock_fd = open("var/lib/apk/lock",
O_CREAT | O_WRONLY, 0400);
}
if (db->lock_fd < 0 ||
flock(db->lock_fd, LOCK_EX | LOCK_NB) < 0) {
if (apk_wait) {
struct sigaction sa, old_sa;
apk_message("Waiting for repository lock");
memset(&sa, 0, sizeof sa);
sa.sa_handler = handle_alarm;
sa.sa_flags = SA_ONESHOT;
sigaction(SIGALRM, &sa, &old_sa);
alarm(apk_wait);
if (flock(db->lock_fd, LOCK_EX) < 0) {
msg = "Unable to lock database";
goto ret_errno;
}
alarm(0);
sigaction(SIGALRM, &old_sa, NULL);
}
blob = APK_BLOB_STR("etc:-etc/init.d");
apk_blob_for_each_segment(blob, ":", add_protected_path, db);
if (root != NULL) {
r = apk_db_read_state(db, flags);
if (r == -ENOENT && (flags & APK_OPENF_CREATE)) {
r = apk_db_create(db);
r = apk_db_read_state(db, flags);
}
if (r != 0) {
msg = "Unable to read database state";
goto ret_r;
if (apk_repos == NULL)
apk_repos = "/etc/apk/repositories";
blob = apk_blob_from_file(apk_repos);
if (!APK_BLOB_IS_NULL(blob)) {
apk_blob_for_each_segment(blob, "\n",
apk_db_add_repository, db);
free(blob.ptr);
}
}
}
list_for_each_entry(repo, &apk_repository_list.list, list)
apk_db_add_repository(db, APK_BLOB_STR(repo->url));
ret_errno:
r = -errno;
ret_r:
if (msg != NULL)
apk_error("%s: %s", msg, strerror(-r));
struct write_ctx {
struct apk_database *db;
int fd;
};
int apk_db_write_config(struct apk_database *db)
{
if (db->root == NULL)
if (db->lock_fd == 0) {
apk_error("Refusing to write db without write lock!");
return -1;
}
fchdir(db->root_fd);
os = apk_ostream_to_file("var/lib/apk/world", 0644);
return -1;
apk_deps_write(db->world, os);
os->write(os, "\n", 1);
os = apk_ostream_to_file("var/lib/apk/installed.new", 0644);
return -1;
if (rename("var/lib/apk/installed.new", "var/lib/apk/installed") < 0)
return -errno;
os = apk_ostream_to_file("var/lib/apk/scripts.tar.new", 0644);
return -1;
if (rename("var/lib/apk/scripts.tar.new", "var/lib/apk/scripts.tar") < 0)
return -errno;
unlink("var/lib/apk/scripts");
return 0;
}
void apk_db_close(struct apk_database *db)
{
struct apk_package *pkg;
struct apk_db_dir_instance *diri;
struct hlist_node *dc, *dn;
int i;
list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) {
hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) {
apk_db_diri_free(db, diri);
}
}
for (i = 0; i < db->num_repos; i++) {
if (db->protected_paths) {
for (i = 0; i < db->protected_paths->num; i++)
free(db->protected_paths->item[i]);
free(db->protected_paths);
}
if (db->world)
free(db->world);
apk_hash_free(&db->available.names);
apk_hash_free(&db->available.packages);
apk_hash_free(&db->installed.files);
apk_hash_free(&db->installed.dirs);
if (db->lock_fd)
close(db->lock_fd);
if (db->root != NULL)
free(db->root);
}
int apk_db_cache_active(struct apk_database *db)
{
return db->cache_dir != apk_static_cache_dir;
}
struct apk_package *apk_db_get_pkg(struct apk_database *db,
struct apk_checksum *csum)
{
return apk_hash_get(&db->available.packages, APK_BLOB_CSUM(*csum));
}
struct apk_package *apk_db_get_file_owner(struct apk_database *db,
apk_blob_t filename)
{
struct apk_db_file *dbf;
struct apk_db_file_hash_key key;
if (filename.len && filename.ptr[0] == '/')
filename.len--, filename.ptr++;
if (!apk_blob_rsplit(filename, '/', &key.dirname, &key.filename))
return NULL;
dbf = (struct apk_db_file *) apk_hash_get(&db->installed.files,
APK_BLOB_BUF(&key));
if (dbf == NULL)
return dbf->diri->pkg;
struct index_write_ctx {
struct apk_ostream *os;
int count;
};
static int write_index_entry(apk_hash_item item, void *ctx)
{
struct index_write_ctx *iwctx = (struct index_write_ctx *) ctx;
struct apk_package *pkg = (struct apk_package *) item;
r = apk_pkg_write_index_entry(pkg, iwctx->os);
if (r < 0)
return r;
if (iwctx->os->write(iwctx->os, "\n", 1) != 1)
return 0;
}
int apk_db_index_write(struct apk_database *db, struct apk_ostream *os)
{
struct index_write_ctx ctx = { os, 0 };
apk_hash_foreach(&db->available.packages, write_index_entry, &ctx);
return ctx.count;
}
static void apk_db_cache_get_name(char *buf, size_t bufsz,