From ea901526648c43ef8e961b3d7e051b9ca14b65ca Mon Sep 17 00:00:00 2001
From: Timo Teras <timo.teras@iki.fi>
Date: Fri, 31 Jul 2009 16:08:09 +0300
Subject: apk: use *at instead of chdir+normal file syscall

this way we never change cwd, and relative filenames are always
parsed consistently. this also helps filename construction in many
places. this patch also changes '--root' to override location of
all configuration to be in the new root. previously it depended
on the file which one was used.
---
 src/Makefile       |   1 +
 src/add.c          |   2 +-
 src/apk.c          |   3 +-
 src/apk_archive.h  |   5 +-
 src/apk_database.h |  12 +-
 src/apk_defines.h  |   2 +-
 src/apk_io.h       |  19 +--
 src/apk_package.h  |   5 +-
 src/archive.c      |  55 ++++-----
 src/audit.c        |   7 +-
 src/cache.c        |  63 +++++-----
 src/database.c     | 330 ++++++++++++++++++++++++-----------------------------
 src/fetch.c        |  54 ++++-----
 src/index.c        |   8 +-
 src/io.c           |  34 +++---
 src/package.c      |  67 ++++++++---
 src/state.c        |   2 +-
 src/url.c          |  21 ++--
 src/verify.c       |  11 +-
 19 files changed, 360 insertions(+), 341 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index 96e36b3..e0e97f1 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -9,6 +9,7 @@ apk-objs		:= state.o database.o package.o archive.o \
 			   version.o io.o url.o gunzip.o blob.o hash.o apk.o \
 			   add.o del.o update.o info.o search.o upgrade.o \
 			   cache.o ver.o index.o fetch.o audit.o verify.o
+CFLAGS			+= -D_ATFILE_SOURCE
 CFLAGS_apk.o		:= -DAPK_VERSION=\"$(FULL_VERSION)\"
 
 progs-$(STATIC)		+= apk.static
diff --git a/src/add.c b/src/add.c
index 003fcfc..e89a4cd 100644
--- a/src/add.c
+++ b/src/add.c
@@ -101,7 +101,7 @@ static int add_main(void *ctx, int argc, char **argv)
 				goto err;
 
 			apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE,
-					  NULL);
+					  NULL, db.keys_fd);
 			r = apk_pkg_read(&db, argv[i], &sctx, &pkg);
 			apk_sign_ctx_free(&sctx);
 			if (r != 0) {
diff --git a/src/apk.c b/src/apk.c
index a21427f..122f9a7 100644
--- a/src/apk.c
+++ b/src/apk.c
@@ -26,7 +26,7 @@
 
 const char *apk_root;
 struct apk_repository_url apk_repository_list;
-int apk_verbosity = 1, apk_cwd_fd, apk_wait;
+int apk_verbosity = 1, apk_wait;
 unsigned int apk_flags = 0;
 
 static struct apk_option generic_options[] = {
@@ -292,7 +292,6 @@ int main(int argc, char **argv)
 	struct apk_repository_url *repo = NULL;
 
 	umask(0);
-	apk_cwd_fd = open(".", O_RDONLY);
 	apk_root = getenv("ROOT");
 	list_init(&apk_repository_list.list);
 
diff --git a/src/apk_archive.h b/src/apk_archive.h
index 320db5e..f983203 100644
--- a/src/apk_archive.h
+++ b/src/apk_archive.h
@@ -27,9 +27,8 @@ int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae,
 			char *data);
 int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
 
-int apk_archive_entry_extract(const struct apk_file_info *ae,
-			      struct apk_istream *is,
-			      const char *to,
+int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
+			      const char *suffix, struct apk_istream *is,
 			      apk_progress_cb cb, void *cb_ctx);
 
 #endif
diff --git a/src/apk_database.h b/src/apk_database.h
index 241719d..094725d 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -80,7 +80,7 @@ struct apk_repository {
 
 struct apk_database {
 	char *root;
-	int root_fd, lock_fd;
+	int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd;
 	unsigned name_id, num_repos;
 	const char *cache_dir;
 	int permanent;
@@ -134,7 +134,6 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
 int apk_db_open(struct apk_database *db, const char *root, unsigned int flags);
 int apk_db_write_config(struct apk_database *db);
 void apk_db_close(struct apk_database *db);
-int apk_db_cache_active(struct apk_database *db);
 int apk_db_permanent(struct apk_database *db);
 
 struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg);
@@ -147,10 +146,11 @@ int apk_db_index_write(struct apk_database *db, struct apk_ostream *os);
 
 int apk_db_add_repository(apk_database_t db, apk_blob_t repository);
 int apk_repository_update(struct apk_database *db, struct apk_repository *repo);
-int apk_cache_download(struct apk_database *db, struct apk_checksum *csum,
-		       const char *url, const char *item, int verify);
-int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum,
-		     const char *item);
+
+int apk_db_cache_active(struct apk_database *db);
+void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo, int ver);
+int apk_cache_download(struct apk_database *db, const char *url,
+		       const char *item, const char *cache_item, int verify);
 
 int apk_db_install_pkg(struct apk_database *db,
 		       struct apk_package *oldpkg,
diff --git a/src/apk_defines.h b/src/apk_defines.h
index 2ce3535..0dc0c20 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -48,7 +48,7 @@
         (type *)( (char *)__mptr - offsetof(type,member) );})
 #endif
 
-extern int apk_cwd_fd, apk_verbosity, apk_wait;
+extern int apk_verbosity, apk_wait;
 extern unsigned int apk_flags;
 
 #define APK_FORCE		0x0001
diff --git a/src/apk_io.h b/src/apk_io.h
index b76385c..759bec4 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -66,8 +66,8 @@ struct apk_ostream *apk_ostream_gzip(struct apk_ostream *);
 struct apk_ostream *apk_ostream_counter(off_t *);
 
 struct apk_istream *apk_istream_from_fd(int fd);
-struct apk_istream *apk_istream_from_file(const char *file);
-struct apk_istream *apk_istream_from_file_gz(const char *file);
+struct apk_istream *apk_istream_from_file(int atfd, const char *file);
+struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file);
 struct apk_istream *apk_istream_from_url(const char *url);
 struct apk_istream *apk_istream_from_url_gz(const char *url);
 size_t apk_istream_skip(struct apk_istream *istream, size_t size);
@@ -76,20 +76,21 @@ size_t apk_istream_splice(void *stream, int fd, size_t size,
 
 struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream);
 struct apk_bstream *apk_bstream_from_fd(int fd);
-struct apk_bstream *apk_bstream_from_file(const char *file);
+struct apk_bstream *apk_bstream_from_file(int atfd, const char *file);
 struct apk_bstream *apk_bstream_from_url(const char *url);
-struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, const char *to);
+struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to);
 
 struct apk_ostream *apk_ostream_to_fd(int fd);
-struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode);
-struct apk_ostream *apk_ostream_to_file_gz(const char *file, mode_t mode);
+struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
+struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, mode_t mode);
 size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
 
 apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size);
-apk_blob_t apk_blob_from_file(const char *file);
+apk_blob_t apk_blob_from_file(int atfd, const char *file);
 
-int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *fi);
-int apk_url_download(const char *url, const char *file);
+int apk_file_get_info(int atfd, const char *filename, int checksum,
+		      struct apk_file_info *fi);
+int apk_url_download(const char *url, int atfd, const char *file);
 const char *apk_url_local_file(const char *url);
 
 #endif
diff --git a/src/apk_package.h b/src/apk_package.h
index 96d7840..791df93 100644
--- a/src/apk_package.h
+++ b/src/apk_package.h
@@ -38,6 +38,7 @@ struct apk_name;
 #define APK_SIGN_VERIFY_AND_GENERATE	5
 
 struct apk_sign_ctx {
+	int keys_fd;
 	int action;
 	const EVP_MD *md;
 	int num_signatures;
@@ -97,7 +98,7 @@ APK_ARRAY(apk_package_array, struct apk_package *);
 extern const char *apk_script_types[];
 
 void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
-		       struct apk_checksum *identity);
+		       struct apk_checksum *identity, int keys_fd);
 void apk_sign_ctx_free(struct apk_sign_ctx *ctx);
 int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
 			      const struct apk_file_info *fi,
@@ -121,6 +122,8 @@ void apk_deps_parse(struct apk_database *db,
 int apk_deps_write(struct apk_dependency_array *deps, struct apk_ostream *os);
 int apk_script_type(const char *name);
 
+void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to);
+void apk_pkg_format_cache(struct apk_package *pkg, apk_blob_t to);
 struct apk_package *apk_pkg_new(void);
 int apk_pkg_read(struct apk_database *db, const char *name,
 		 struct apk_sign_ctx *ctx, struct apk_package **pkg);
diff --git a/src/archive.c b/src/archive.c
index 31c0909..e20caa7 100644
--- a/src/archive.c
+++ b/src/archive.c
@@ -309,29 +309,28 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae
 	return 0;
 }
 
-int apk_archive_entry_extract(const struct apk_file_info *ae,
-			      struct apk_istream *is,
-			      const char *fn, apk_progress_cb cb,
-			      void *cb_ctx)
+int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
+			      const char *suffix, struct apk_istream *is,
+			      apk_progress_cb cb, void *cb_ctx)
 {
-	struct utimbuf utb;
-	int r = -1, fd;
+	char *fn = ae->name;
+	int fd, r = -1, atflags = 0;
 
-	if (fn == NULL)
-		fn = ae->name;
-
-	/* BIG HONKING FIXME */
-	unlink(fn);
+	if (suffix != NULL) {
+		fn = alloca(PATH_MAX);
+		snprintf(fn, PATH_MAX, "%s%s", ae->name, suffix);
+	}
+	unlinkat(atfd, fn, 0);
 
 	switch (ae->mode & S_IFMT) {
 	case S_IFDIR:
-		r = mkdir(fn, ae->mode & 07777);
+		r = mkdirat(atfd, fn, ae->mode & 07777);
 		if (r < 0 && errno == EEXIST)
 			r = 0;
 		break;
 	case S_IFREG:
 		if (ae->link_target == NULL) {
-			fd = open(fn, O_RDWR | O_CREAT, ae->mode & 07777);
+			fd = openat(atfd, fn, O_RDWR | O_CREAT, ae->mode & 07777);
 			if (fd < 0) {
 				r = -1;
 				break;
@@ -341,27 +340,28 @@ int apk_archive_entry_extract(const struct apk_file_info *ae,
 				r = 0;
 			close(fd);
 		} else {
-			char link_target[PATH_MAX];
-			snprintf(link_target, sizeof(link_target),
-				 "%s.apk-new", ae->link_target);
-			r = link(link_target, fn);
+			char *link_target = ae->link_target;
+			if (suffix != NULL) {
+				link_target = alloca(PATH_MAX);
+				snprintf(link_target, PATH_MAX, "%s%s",
+					 ae->link_target, suffix);
+			}
+			r = linkat(atfd, link_target, atfd, fn, 0);
 		}
 		break;
 	case S_IFLNK:
-		r = symlink(ae->link_target, fn);
+		r = symlinkat(ae->link_target, atfd, fn);
+		atflags |= AT_SYMLINK_NOFOLLOW;
 		break;
 	case S_IFSOCK:
 	case S_IFBLK:
 	case S_IFCHR:
 	case S_IFIFO:
-		r = mknod(fn, ae->mode & 07777, ae->device);
+		r = mknodat(atfd, fn, ae->mode & 07777, ae->device);
 		break;
 	}
 	if (r == 0) {
-		if (!S_ISLNK(ae->mode))
-			r = chown(fn, ae->uid, ae->gid);
-		else
-			r = lchown(fn, ae->uid, ae->gid);
+		r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
 		if (r < 0) {
 			apk_error("Failed to set ownership on %s: %s",
 				  fn, strerror(errno));
@@ -370,7 +370,7 @@ int apk_archive_entry_extract(const struct apk_file_info *ae,
 
 		/* chown resets suid bit so we need set it again */
 		if (ae->mode & 07000) {
-			r = chmod(fn, ae->mode & 07777);
+			r = fchmodat(atfd, fn, ae->mode & 07777, atflags);
 			if (r < 0) {
 				apk_error("Failed to set file permissions "
 					  "on %s: %s",
@@ -381,8 +381,11 @@ int apk_archive_entry_extract(const struct apk_file_info *ae,
 
 		if (!S_ISLNK(ae->mode)) {
 			/* preserve modification time */
-			utb.actime = utb.modtime = ae->mtime;
-			r = utime(fn, &utb);
+			struct timespec times[2];
+
+			times[0].tv_sec  = times[1].tv_sec  = ae->mtime;
+			times[0].tv_nsec = times[1].tv_nsec = 0;
+			r = utimensat(atfd, fn, times, atflags);
 			if (r < 0) {
 				apk_error("Failed to preserve modification time on %s: %s",
 					fn, strerror(errno));
diff --git a/src/audit.c b/src/audit.c
index 76bd492..6191a2c 100644
--- a/src/audit.c
+++ b/src/audit.c
@@ -11,6 +11,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <sys/stat.h>
@@ -42,7 +43,7 @@ static int audit_directory(apk_hash_item item, void *ctx)
 	if (!(actx->type & AUDIT_BACKUP) && (dbd->flags & APK_DBDIRF_PROTECTED))
 		return 0;
 
-	dir = opendir(dbd->name);
+	dir = fdopendir(openat(db->root_fd, dbd->name, O_RDONLY));
 	if (dir == NULL)
 		return 0;
 
@@ -53,7 +54,7 @@ static int audit_directory(apk_hash_item item, void *ctx)
 
 		snprintf(tmp, sizeof(tmp), "%s/%s", dbd->name, de->d_name);
 
-		if (apk_file_get_info(tmp, APK_CHECKSUM_NONE, &fi) < 0)
+		if (apk_file_get_info(db->root_fd, tmp, APK_CHECKSUM_NONE, &fi) < 0)
 			continue;
 
 		if (!(actx->type & AUDIT_SYSTEM) &&
@@ -70,7 +71,7 @@ static int audit_directory(apk_hash_item item, void *ctx)
 			dbf = apk_db_file_query(db, bdir, APK_BLOB_STR(de->d_name));
 			if (dbf != NULL) {
 				if (dbf->csum.type != APK_CHECKSUM_NONE &&
-				    apk_file_get_info(tmp, dbf->csum.type, &fi) == 0 &&
+				    apk_file_get_info(db->root_fd, tmp, dbf->csum.type, &fi) == 0 &&
 				    apk_checksum_compare(&fi.csum, &dbf->csum) == 0)
 					continue;
 
diff --git a/src/cache.c b/src/cache.c
index ac2281e..c961fc9 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -28,7 +28,7 @@ static int cache_download(struct apk_database *db)
 	struct apk_state *state;
 	struct apk_change *change;
 	struct apk_package *pkg;
-	char pkgfile[256];
+	char item[PATH_MAX], cacheitem[PATH_MAX];
 	int i, r;
 
 	if (db->world == NULL)
@@ -38,24 +38,27 @@ static int cache_download(struct apk_database *db)
 	for (i = 0; i < db->world->num; i++) {
 		r = apk_state_lock_dependency(state, &db->world->item[i]);
 		if (r != 0) {
-			apk_error("Unable to select version for '%s'",
-				  db->world->item[i].name->name);
+			apk_error("Unable to select version for '%s': %d",
+				  db->world->item[i].name->name, r);
 			goto err;
 		}
 	}
 
 	list_for_each_entry(change, &state->change_list_head, change_list) {
 		pkg = change->newpkg;
-		snprintf(pkgfile, sizeof(pkgfile), "%s-%s.apk",
-			 pkg->name->name, pkg->version);
-		if (apk_cache_exists(db, &pkg->csum, pkgfile))
+
+		apk_pkg_format_cache(pkg, APK_BLOB_BUF(cacheitem));
+		if (faccessat(db->cache_fd, cacheitem, R_OK, 0) == 0)
 			continue;
+
 		for (i = 0; i < db->num_repos; i++) {
 			if (!(pkg->repos & BIT(i)))
 				continue;
 
-			r = apk_cache_download(db, &pkg->csum, db->repos[i].url,
-					       pkgfile, APK_SIGN_VERIFY_IDENTITY);
+			apk_pkg_format_plain(pkg, APK_BLOB_BUF(item));
+			r = apk_cache_download(db, db->repos[i].url,
+					       item, cacheitem,
+					       APK_SIGN_VERIFY_IDENTITY);
 			if (r != 0)
 				return r;
 		}
@@ -68,54 +71,54 @@ err:
 
 static int cache_clean(struct apk_database *db)
 {
+	char tmp[PATH_MAX];
 	DIR *dir;
 	struct dirent *de;
-	char path[256], csum[APK_CACHE_CSUM_BYTES];
 	int delete, i;
 	apk_blob_t b, bname, bver;
 	struct apk_name *name;
 
-	snprintf(path, sizeof(path), "%s/%s", db->root, db->cache_dir);
-	if (chdir(path) != 0)
-		return -1;
-
-	dir = opendir(path);
+	dir = fdopendir(dup(db->cache_fd));
 	if (dir == NULL)
 		return -1;
 
 	while ((de = readdir(dir)) != NULL) {
 		if (de->d_name[0] == '.')
 			continue;
+
 		delete = TRUE;
 		do {
 			b = APK_BLOB_STR(de->d_name);
-			apk_blob_pull_hexdump(&b, APK_BLOB_BUF(csum));
-			apk_blob_pull_char(&b, '.');
 
-			if (apk_blob_compare(b, APK_BLOB_STR(apk_index_gz)) == 0 ||
-			    apk_blob_compare(b, APK_BLOB_STR(apkindex_tar_gz)) == 0) {
+			if (apk_blob_compare(b, APK_BLOB_STR("installed")) == 0) {
+				delete = FALSE;
+				break;
+			}
+
+			if (apk_pkg_parse_name(b, &bname, &bver) < 0) {
 				/* Index - check for matching repository */
 				for (i = 0; i < db->num_repos; i++) {
-					if (memcmp(db->repos[i].csum.data,
-						   csum, APK_CACHE_CSUM_BYTES) != 0)
-						continue;
+					apk_cache_format_index(APK_BLOB_BUF(tmp), &db->repos[i], 0);
+					if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0) {
+						apk_cache_format_index(APK_BLOB_BUF(tmp), &db->repos[i], 1);
+						if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0)
+							continue;
+					}
 					delete = 0;
 					break;
 				}
-			} else if (b.len > 4 &&
-				   memcmp(b.ptr+b.len-4, ".apk", 4) == 0) {
+			} else {
 				/* Package - search for it */
-				if (apk_pkg_parse_name(b, &bname, &bver) < 0)
-					break;
-
 				name = apk_db_get_name(db, bname);
 				if (name == NULL || name->pkgs == NULL)
 					break;
-
 				for (i = 0; i < name->pkgs->num; i++) {
 					struct apk_package *pkg = name->pkgs->item[i];
-					if (memcmp(pkg->csum.data, csum, APK_CACHE_CSUM_BYTES) != 0)
+
+					apk_pkg_format_cache(pkg, APK_BLOB_BUF(tmp));
+					if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0)
 						continue;
+
 					delete = 0;
 					break;
 				}
@@ -126,7 +129,7 @@ static int cache_clean(struct apk_database *db)
 			if (apk_verbosity >= 2)
 				apk_message("deleting %s", de->d_name);
 			if (!(apk_flags & APK_SIMULATE))
-				unlink(de->d_name);
+				unlinkat(db->cache_fd, de->d_name, 0);
 		}
 	}
 
@@ -152,7 +155,7 @@ static int cache_main(void *ctx, int argc, char **argv)
 	else
 		return -EINVAL;
 
-	r = apk_db_open(&db, apk_root,
+	r = apk_db_open(&db, apk_root, APK_OPENF_READ |
 			APK_OPENF_NO_SCRIPTS | APK_OPENF_NO_INSTALLED);
 	if (r != 0)
 		return r;
diff --git a/src/database.c b/src/database.c
index 15e4730..e71f4c2 100644
--- a/src/database.c
+++ b/src/database.c
@@ -285,16 +285,16 @@ static void apk_db_diri_set(struct apk_db_dir_instance *diri, mode_t mode,
 	diri->gid = gid;
 }
 
-static void apk_db_diri_mkdir(struct apk_db_dir_instance *diri)
+static void apk_db_diri_mkdir(struct apk_database *db, struct apk_db_dir_instance *diri)
 {
-	if (mkdir(diri->dir->name, diri->mode) == 0)
-		chown(diri->dir->name, diri->uid, diri->gid);
+	if (mkdirat(db->root_fd, diri->dir->name, diri->mode) == 0)
+		fchownat(db->root_fd, diri->dir->name, diri->uid, diri->gid, 0);
 }
 
-static void apk_db_diri_rmdir(struct apk_db_dir_instance *diri)
+static void apk_db_diri_rmdir(struct apk_database *db, struct apk_db_dir_instance *diri)
 {
 	if (diri->dir->refs == 1)
-		rmdir(diri->dir->name);
+		unlinkat(db->root_fd, diri->dir->name, 1);
 }
 
 static void apk_db_diri_free(struct apk_database *db,
@@ -409,21 +409,62 @@ struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *
 	return idb;
 }
 
-static void apk_db_cache_get_name(char *buf, size_t bufsz,
-				  struct apk_database *db,
-				  struct apk_checksum *csum,
-				  const char *file, int temp)
+void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo, int ver)
 {
-	char csumstr[APK_CACHE_CSUM_BYTES*2+1];
-	apk_blob_t bbuf = APK_BLOB_BUF(csumstr);
+	/* APKINDEX.12345678.tar.gz */
+	/* APK_INDEX.12345678.gz */
+	if (ver == 0)
+		apk_blob_push_blob(&to, APK_BLOB_STR("APKINDEX."));
+	else
+		apk_blob_push_blob(&to, APK_BLOB_STR("APK_INDEX."));
+	apk_blob_push_hexdump(&to, APK_BLOB_PTR_LEN((char *) repo->csum.data,
+						    APK_CACHE_CSUM_BYTES));
+	if (ver == 0)
+		apk_blob_push_blob(&to, APK_BLOB_STR(".tar.gz"));
+	else
+		apk_blob_push_blob(&to, APK_BLOB_STR(".gz"));
+	apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
+}
+
+int apk_cache_download(struct apk_database *db, const char *url,
+		       const char *item, const char *cacheitem, int verify)
+{
+	char fullurl[PATH_MAX];
+	int r;
+
+	snprintf(fullurl, sizeof(fullurl), "%s%s%s",
+		 url, url[strlen(url)-1] == '/' ? "" : "/", item);
+	apk_message("fetch %s", fullurl);
+
+	if (apk_flags & APK_SIMULATE)
+		return 0;
+
+	r = apk_url_download(fullurl, db->cachetmp_fd, cacheitem);
+	if (r < 0)
+		return r;
+
+	if (verify != APK_SIGN_NONE) {
+		struct apk_istream *is;
+		struct apk_sign_ctx sctx;
+
+		apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd);
+		is = apk_bstream_gunzip_mpart(
+			apk_bstream_from_file(db->cachetmp_fd, cacheitem),
+			apk_sign_ctx_mpart_cb, &sctx);
+
+		r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE);
+		is->close(is);
+		apk_sign_ctx_free(&sctx);
+		if (r != 0) {
+			unlinkat(db->cachetmp_fd, cacheitem, 0);
+			return r;
+		}
+	}
 
-	apk_blob_push_hexdump(&bbuf,
-			      APK_BLOB_PTR_LEN((char *) csum->data,
-			      APK_CACHE_CSUM_BYTES));
-	apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN("", 1));
+	if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0)
+		return -errno;
 
-	snprintf(buf, bufsz, "%s/%s/%s.%s%s",
-		 db->root, db->cache_dir, csumstr, file, temp ? ".new" : "");
+	return 0;
 }
 
 int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
@@ -690,10 +731,8 @@ static int apk_db_read_state(struct apk_database *db, int flags)
 	 * 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");
+		blob = apk_blob_from_file(db->root_fd, "var/lib/apk/world");
 		if (APK_BLOB_IS_NULL(blob))
 			return -ENOENT;
 		apk_deps_parse(db, &db->world, blob);
@@ -704,13 +743,13 @@ static int apk_db_read_state(struct apk_database *db, int flags)
 	}
 
 	if (!(flags & APK_OPENF_NO_INSTALLED)) {
-		bs = apk_bstream_from_file("var/lib/apk/installed");
+		bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/installed");
 		if (bs != NULL) {
 			apk_db_index_read(db, bs, -1);
 			bs->close(bs, NULL);
 		}
 
-		bs = apk_bstream_from_file("etc/apk/cache/installed");
+		bs = apk_bstream_from_file(db->cache_fd, "installed");
 		if (bs != NULL) {
 			apk_db_index_read(db, bs, -2);
 			bs->close(bs, NULL);
@@ -718,12 +757,12 @@ static int apk_db_read_state(struct apk_database *db, int flags)
 	}
 
 	if (!(flags & APK_OPENF_NO_SCRIPTS)) {
-		is = apk_istream_from_file("var/lib/apk/scripts.tar");
+		is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar");
 		if (is != NULL) {
 			apk_tar_parse(is, apk_read_script_archive_entry, db,
 				      FALSE);
 		} else {
-			is = apk_istream_from_file("var/lib/apk/scripts");
+			is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts");
 			if (is != NULL)
 				apk_db_scriptdb_read_v1(db, is);
 		}
@@ -772,10 +811,11 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
 
 	/* Write list of installed non-repository packages to
 	 * cached index file */
-	ctx.os = os = apk_ostream_to_file("etc/apk/cache/installed.new", 0644);
+	os = apk_ostream_to_file(db->cache_fd, "installed.new", 0644);
 	if (os == NULL)
 		return -1;
 
+	ctx.os = os;
 	list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) {
 		if (pkg->repos != 0)
 			continue;
@@ -785,8 +825,8 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
 	}
 
 	os->close(os);
-	if (rename("etc/apk/cache/installed.new",
-		   "etc/apk/cache/installed") < 0)
+	if (renameat(db->cache_fd, "installed.new",
+		     db->cache_fd, "installed") < 0)
 			return -errno;
 
 	return ctx.count;
@@ -815,15 +855,14 @@ static int apk_db_create(struct apk_database *db)
 				       "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);
+	mkdirat(db->root_fd, "tmp", 01777);
+	mkdirat(db->root_fd, "dev", 0755);
+	mknodat(db->root_fd, "dev/null", 0666, makedev(1, 3));
+	mkdirat(db->root_fd, "var", 0755);
+	mkdirat(db->root_fd, "var/lib", 0755);
+	mkdirat(db->root_fd, "var/lib/apk", 0755);
 
-	fd = creat("var/lib/apk/world", 0644);
+	fd = openat(db->root_fd, "var/lib/apk/world", O_CREAT|O_RDWR|O_TRUNC, 0644);
 	if (fd < 0)
 		return -errno;
 	write(fd, deps.ptr, deps.len);
@@ -840,7 +879,7 @@ 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;
+	struct stat64 st;
 	apk_blob_t blob;
 	int r;
 
@@ -854,27 +893,26 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
 	db->permanent = 1;
 
 	if (root != NULL) {
-		fchdir(apk_cwd_fd);
 		db->root = strdup(root);
-		db->root_fd = open(root, O_RDONLY);
+		db->root_fd = openat(AT_FDCWD, db->root, O_RDONLY);
 		if (db->root_fd < 0 && (flags & APK_OPENF_CREATE)) {
-			mkdir(db->root, 0755);
-			db->root_fd = open(root, O_RDONLY);
+			mkdirat(AT_FDCWD, db->root, 0755);
+			db->root_fd = openat(AT_FDCWD, root, O_RDONLY);
 		}
 		if (db->root_fd < 0) {
 			msg = "Unable to open root";
 			goto ret_errno;
 		}
-		if (fstat(db->root_fd, &st) != 0 || major(st.st_dev) == 0)
+		if (fstat64(db->root_fd, &st) != 0 || major(st.st_dev) == 0)
 			db->permanent = 0;
 
-		fchdir(db->root_fd);
-		if (stat(apk_linked_cache_dir, &st) == 0 && S_ISDIR(st.st_mode))
+		if (fstatat64(db->root_fd, apk_linked_cache_dir, &st, 0) == 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);
+			db->lock_fd = openat(db->root_fd, "var/lib/apk/lock",
+					     O_CREAT | O_RDWR, 0400);
 			if (db->lock_fd < 0 && errno == ENOENT &&
 			    (flags & APK_OPENF_CREATE)) {
 				r = apk_db_create(db);
@@ -882,8 +920,9 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
 					msg = "Unable to create database";
 					goto ret_r;
 				}
-				db->lock_fd = open("var/lib/apk/lock",
-						   O_CREAT | O_WRONLY, 0400);
+				db->lock_fd = openat(db->root_fd,
+						     "var/lib/apk/lock",
+						     O_CREAT | O_RDWR, 0400);
 			}
 			if (db->lock_fd < 0 ||
 			    flock(db->lock_fd, LOCK_EX | LOCK_NB) < 0) {
@@ -912,6 +951,11 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
 	blob = APK_BLOB_STR("etc:*etc/init.d");
 	apk_blob_for_each_segment(blob, ":", add_protected_path, db);
 
+	db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY);
+	mkdirat(db->cache_fd, "tmp", 0644);
+	db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY);
+	db->keys_fd = openat(db->root_fd, "etc/apk/keys", O_RDONLY);
+
 	if (root != NULL) {
 		r = apk_db_read_state(db, flags);
 		if (r == -ENOENT && (flags & APK_OPENF_CREATE)) {
@@ -929,8 +973,8 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
 
 		if (!(flags & APK_OPENF_NO_REPOS)) {
 			if (apk_repos == NULL)
-				apk_repos = "/etc/apk/repositories";
-			blob = apk_blob_from_file(apk_repos);
+				apk_repos = "etc/apk/repositories";
+			blob = apk_blob_from_file(db->root_fd, apk_repos);
 			if (!APK_BLOB_IS_NULL(blob)) {
 				apk_blob_for_each_segment(blob, "\n",
 							  apk_db_add_repository, db);
@@ -947,7 +991,6 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags)
 			apk_db_index_write_nr_cache(db);
 	}
 
-	fchdir(apk_cwd_fd);
 	return 0;
 
 ret_errno:
@@ -956,7 +999,7 @@ ret_r:
 	if (msg != NULL)
 		apk_error("%s: %s", msg, strerror(-r));
 	apk_db_close(db);
-	fchdir(apk_cwd_fd);
+
 	return r;
 }
 
@@ -977,35 +1020,36 @@ int apk_db_write_config(struct apk_database *db)
 		return -1;
 	}
 
-	fchdir(db->root_fd);
-
-	os = apk_ostream_to_file("var/lib/apk/world.new", 0644);
+	os = apk_ostream_to_file(db->root_fd, "var/lib/apk/world.new", 0644);
 	if (os == NULL)
 		return -1;
 	apk_deps_write(db->world, os);
 	os->write(os, "\n", 1);
 	os->close(os);
-	if (rename("var/lib/apk/world.new", "var/lib/apk/world") < 0)
+	if (renameat(db->root_fd, "var/lib/apk/world.new",
+	             db->root_fd, "var/lib/apk/world") < 0)
 		return -errno;
 
-	os = apk_ostream_to_file("var/lib/apk/installed.new", 0644);
+	os = apk_ostream_to_file(db->root_fd, "var/lib/apk/installed.new", 0644);
 	if (os == NULL)
 		return -1;
 	apk_db_write_fdb(db, os);
 	os->close(os);
 
-	if (rename("var/lib/apk/installed.new", "var/lib/apk/installed") < 0)
+	if (renameat(db->root_fd, "var/lib/apk/installed.new",
+		     db->root_fd, "var/lib/apk/installed") < 0)
 		return -errno;
 
-	os = apk_ostream_to_file("var/lib/apk/scripts.tar.new", 0644);
+	os = apk_ostream_to_file(db->root_fd, "var/lib/apk/scripts.tar.new", 0644);
 	if (os == NULL)
 		return -1;
 	apk_db_scriptdb_write(db, os);
 	os->close(os);
-	if (rename("var/lib/apk/scripts.tar.new", "var/lib/apk/scripts.tar") < 0)
+	if (renameat(db->root_fd, "var/lib/apk/scripts.tar.new",
+		     db->root_fd, "var/lib/apk/scripts.tar") < 0)
 		return -errno;
 
-	unlink("var/lib/apk/scripts");
+	unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
 	apk_db_index_write_nr_cache(db);
 
 	return 0;
@@ -1040,6 +1084,12 @@ void apk_db_close(struct apk_database *db)
 	apk_hash_free(&db->installed.files);
 	apk_hash_free(&db->installed.dirs);
 
+	if (db->keys_fd)
+		close(db->keys_fd);
+	if (db->cachetmp_fd)
+		close(db->cachetmp_fd);
+	if (db->cache_fd)
+		close(db->cache_fd);
 	if (db->root_fd)
 		close(db->root_fd);
 	if (db->lock_fd)
@@ -1084,19 +1134,6 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db,
 	return dbf->diri->pkg;
 }
 
-static struct apk_bstream *apk_db_cache_open(struct apk_database *db,
-					     struct apk_checksum *csum,
-					     const char *file)
-{
-	char tmp[256];
-
-	if (db->root == NULL)
-		return NULL;
-
-	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, file, FALSE);
-	return apk_bstream_from_file(tmp);
-}
-
 static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo,
 						    const char *file)
 {
@@ -1109,91 +1146,26 @@ static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo,
 	return apk_bstream_from_url(tmp);
 }
 
-int apk_cache_download(struct apk_database *db, struct apk_checksum *csum,
-		       const char *url, const char *item, int verify)
-{
-	char tmp[256], tmp2[256];
-	int r;
-
-	snprintf(tmp, sizeof(tmp), "%s%s%s",
-		 url, url[strlen(url)-1] == '/' ? "" : "/", item);
-	apk_message("fetch %s", tmp);
-
-	if (apk_flags & APK_SIMULATE)
-		return 0;
-
-	apk_db_cache_get_name(tmp2, sizeof(tmp2), db, csum, item, TRUE);
-	r = apk_url_download(tmp, tmp2);
-	if (r < 0)
-		return r;
-
-	if (verify != APK_SIGN_NONE) {
-		struct apk_istream *is;
-		struct apk_sign_ctx sctx;
-
-		apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
-		is = apk_bstream_gunzip_mpart(apk_bstream_from_file(tmp2),
-			apk_sign_ctx_mpart_cb, &sctx);
-		r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE);
-		is->close(is);
-		apk_sign_ctx_free(&sctx);
-		if (r != 0) {
-			unlink(tmp2);
-			return r;
-		}
-	}
-
-	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
-	if (rename(tmp2, tmp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum,
-		     const char *item)
-{
-	char tmp[256];
-
-	if (db->root == NULL)
-		return 0;
-
-	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
-	return access(tmp, R_OK | W_OK) == 0;
-}
-
-static int apk_cache_delete(struct apk_database *db, struct apk_checksum *csum,
-			    const char *item)
-{
-	char tmp[256];
-
-	if (db->root == NULL)
-		return 0;
-
-	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
-	return unlink(tmp);
-}
-
 int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
 {
+	char cacheitem[PATH_MAX];
 	int r;
 
 	if (repo->csum.type == APK_CHECKSUM_NONE)
 		return 0;
 
-	r = apk_cache_download(db, &repo->csum, repo->url, apkindex_tar_gz,
+	apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 0);
+	r = apk_cache_download(db, repo->url, apkindex_tar_gz, cacheitem,
 			       (apk_flags & APK_ALLOW_UNTRUSTED) ?
 			       APK_SIGN_NONE : APK_SIGN_VERIFY);
 	if (r == 0 || r == -ENOKEY || r == -EKEYREJECTED) {
-		if (r == -ENOKEY)
-			apk_error("%s: verify: UNTRUSTED", repo->url);
-		else if (r == -EKEYREJECTED)
-			apk_error("%s: verify: FAILED", repo->url);
-		apk_cache_delete(db, &repo->csum, apk_index_gz);
+		if (r != 0)
+			apk_error("%s: %s", repo->url, apk_error_str(r));
 		return r;
 	}
 
-	r = apk_cache_download(db, &repo->csum, repo->url, apk_index_gz,
+	apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 1);
+	r = apk_cache_download(db, repo->url, apk_index_gz, cacheitem,
 			       APK_SIGN_NONE);
 	if (r != 0)
 		apk_error("Failed to update %s: download failed", repo->url);
@@ -1238,7 +1210,7 @@ static int load_index(struct apk_database *db, struct apk_bstream *bs,
 		ctx.db = db;
 		ctx.repo = repo;
 		ctx.found = 0;
-		apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL);
+		apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, db->keys_fd);
 		is = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx);
 		r = apk_tar_parse(is, load_apkindex, &ctx, FALSE);
 		is->close(is);
@@ -1260,7 +1232,7 @@ int apk_db_index_read_file(struct apk_database *db, const char *file, int repo)
 	if (strstr(file, ".tar.gz") == NULL && strstr(file, ".gz") != NULL)
 		targz = 0;
 
-	return load_index(db, apk_bstream_from_file(file), targz, repo);
+	return load_index(db, apk_bstream_from_file(AT_FDCWD, file), targz, repo);
 }
 
 int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
@@ -1285,14 +1257,18 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
 	};
 
 	if (apk_url_local_file(repo->url) == NULL) {
+		char cacheitem[PATH_MAX];
+
 		apk_blob_checksum(repository, apk_default_checksum(), &repo->csum);
 
 		if (apk_flags & APK_UPDATE_CACHE)
 			apk_repository_update(db, repo);
 
-		bs = apk_db_cache_open(db, &repo->csum, apkindex_tar_gz);
+		apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 0);
+		bs = apk_bstream_from_file(db->cache_fd, cacheitem);
 		if (bs == NULL) {
-			bs = apk_db_cache_open(db, &repo->csum, apk_index_gz);
+			apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 1);
+			bs = apk_bstream_from_file(db->cache_fd, cacheitem);
 			targz = 0;
 		}
 	} else {
@@ -1356,7 +1332,6 @@ static int apk_db_install_archive_entry(void *_ctx,
 	apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile;
 	struct apk_db_dir_instance *diri = ctx->diri;
 	struct apk_db_file *file;
-	char alt_name[PATH_MAX];
 	const char *p;
 	int r = 0, type = APK_SCRIPT_INVALID;
 
@@ -1455,9 +1430,7 @@ static int apk_db_install_archive_entry(void *_ctx,
 			apk_message("%s", ae->name);
 
 		/* Extract the file as name.apk-new */
-		snprintf(alt_name, sizeof(alt_name), "%s/%s.apk-new",
-			 diri->dir->name, file->name);
-		r = apk_archive_entry_extract(ae, is, alt_name,
+		r = apk_archive_entry_extract(db->root_fd, ae, ".apk-new", is,
 					      extract_cb, ctx);
 		memcpy(&file->csum, &ae->csum, sizeof(file->csum));
 	} else {
@@ -1474,7 +1447,7 @@ static int apk_db_install_archive_entry(void *_ctx,
 		ctx->file_diri_node = hlist_tail_ptr(&diri->owned_files);
 
 		apk_db_diri_set(diri, ae->mode & 0777, ae->uid, ae->gid);
-		apk_db_diri_mkdir(diri);
+		apk_db_diri_mkdir(db, diri);
 	}
 	ctx->installed_size += ctx->current_file_size;
 
@@ -1505,9 +1478,9 @@ static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg,
 			if (!(diri->dir->flags & APK_DBDIRF_PROTECTED) ||
 			    (apk_flags & APK_PURGE) ||
 			    (file->csum.type != APK_CHECKSUM_NONE &&
-			     apk_file_get_info(name, file->csum.type, &fi) == 0 &&
+			     apk_file_get_info(db->root_fd, name, file->csum.type, &fi) == 0 &&
 			     apk_checksum_compare(&file->csum, &fi.csum) == 0))
-				unlink(name);
+				unlinkat(db->root_fd, name, 0);
 			if (apk_verbosity >= 3)
 				apk_message("%s", name);
 			__hlist_del(fc, &diri->owned_files.first);
@@ -1516,7 +1489,7 @@ static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg,
 				db->installed.stats.files--;
 			}
 		}
-		apk_db_diri_rmdir(diri);
+		apk_db_diri_rmdir(db, diri);
 		__hlist_del(dc, &pkg->owned_dirs.first);
 		apk_db_diri_free(db, diri);
 	}
@@ -1564,7 +1537,7 @@ static void apk_db_migrate_files(struct apk_database *db,
 			    (diri->dir->flags & APK_DBDIRF_PROTECTED))
 				cstype = ofile->csum.type;
 
-			r = apk_file_get_info(name, cstype, &fi);
+			r = apk_file_get_info(db->root_fd, name, cstype, &fi);
 			if ((diri->dir->flags & APK_DBDIRF_PROTECTED) &&
 			    (r == 0) &&
 			    (ofile == NULL ||
@@ -1577,14 +1550,15 @@ static void apk_db_migrate_files(struct apk_database *db,
 				 * existing file */
 				if (ofile == NULL ||
 				    ofile->csum.type != file->csum.type)
-					apk_file_get_info(name, file->csum.type, &fi);
+					apk_file_get_info(db->root_fd, name, file->csum.type, &fi);
 				if ((apk_flags & APK_CLEAN_PROTECTED) ||
 				    (file->csum.type != APK_CHECKSUM_NONE &&
 				     apk_checksum_compare(&file->csum, &fi.csum) == 0))
-					unlink(tmpname);
+					unlinkat(db->root_fd, tmpname, 0);
 			} else {
 				/* Overwrite the old file */
-				rename(tmpname, name);
+				renameat(db->root_fd, tmpname,
+					 db->root_fd, name);
 			}
 
 			/* Claim ownership of the file in db */
@@ -1608,12 +1582,9 @@ static int apk_db_unpack_pkg(struct apk_database *db,
 	struct install_ctx ctx;
 	struct apk_bstream *bs = NULL;
 	struct apk_istream *tar;
-	char pkgname[256], file[256];
+	char file[PATH_MAX];
 	int r, i, need_copy = FALSE;
 
-	snprintf(pkgname, sizeof(pkgname), "%s-%s.apk",
-		 newpkg->name->name, newpkg->version);
-
 	if (newpkg->filename == NULL) {
 		struct apk_repository *repo;
 
@@ -1629,24 +1600,26 @@ static int apk_db_unpack_pkg(struct apk_database *db,
 
 		repo = &db->repos[i];
 		if (apk_db_cache_active(db) &&
-		    repo->csum.type != APK_CHECKSUM_NONE)
-			bs = apk_db_cache_open(db, &newpkg->csum, pkgname);
+		    repo->csum.type != APK_CHECKSUM_NONE) {
+			apk_pkg_format_cache(newpkg, APK_BLOB_BUF(file));
+			bs = apk_bstream_from_file(db->cache_fd, file);
+		}
 
 		if (bs == NULL) {
-			bs = apk_repository_file_open(repo, pkgname);
+			apk_pkg_format_plain(newpkg, APK_BLOB_BUF(file));
+			bs = apk_repository_file_open(repo, file);
 			if (repo->csum.type != APK_CHECKSUM_NONE)
 				need_copy = TRUE;
 		}
 	} else {
-		bs = apk_bstream_from_file(newpkg->filename);
+		bs = apk_bstream_from_file(AT_FDCWD, newpkg->filename);
 		need_copy = TRUE;
 	}
 	if (!apk_db_cache_active(db))
 		need_copy = FALSE;
 	if (need_copy) {
-		apk_db_cache_get_name(file, sizeof(file), db, &newpkg->csum,
-				      pkgname, TRUE);
-		bs = apk_bstream_tee(bs, file);
+		apk_pkg_format_cache(newpkg, APK_BLOB_BUF(file));
+		bs = apk_bstream_tee(bs, db->cachetmp_fd, file);
 	}
 
 	if (bs == NULL) {
@@ -1662,7 +1635,7 @@ static int apk_db_unpack_pkg(struct apk_database *db,
 		.cb = cb,
 		.cb_ctx = cb_ctx,
 	};
-	apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum);
+	apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum, db->keys_fd);
 	tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx);
 	r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx, TRUE);
 	apk_sign_ctx_free(&ctx.sctx);
@@ -1680,12 +1653,8 @@ static int apk_db_unpack_pkg(struct apk_database *db,
 
 	apk_db_migrate_files(db, newpkg);
 
-	if (need_copy) {
-		char file2[256];
-		apk_db_cache_get_name(file2, sizeof(file2), db,
-				      &newpkg->csum, pkgname, FALSE);
-		rename(file, file2);
-	}
+	if (need_copy)
+		renameat(db->cachetmp_fd, file, db->cache_fd, file);
 
 	return 0;
 err:
@@ -1700,9 +1669,6 @@ int apk_db_install_pkg(struct apk_database *db,
 {
 	int r;
 
-	if (fchdir(db->root_fd) < 0)
-		return errno;
-
 	/* Just purging? */
 	if (oldpkg != NULL && newpkg == NULL) {
 		r = apk_pkg_run_script(oldpkg, db->root_fd,
diff --git a/src/fetch.c b/src/fetch.c
index c64590e..f93e465 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -11,6 +11,7 @@
 
 #include <stdio.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <unistd.h>
 #include <errno.h>
 #include <zlib.h>
@@ -26,7 +27,7 @@
 
 struct fetch_ctx {
 	unsigned int flags;
-	const char *outdir;
+	int outdir_fd;
 };
 
 static int cup(void)
@@ -80,7 +81,7 @@ static int fetch_parse(void *ctx, int optch, int optindex, const char *optarg)
 		fctx->flags |= FETCH_LINK;
 		break;
 	case 'o':
-		fctx->outdir = optarg;
+		fctx->outdir_fd = openat(AT_FDCWD, optarg, O_RDONLY);
 		break;
 	default:
 		return -1;
@@ -93,22 +94,21 @@ static int fetch_package(struct fetch_ctx *fctx,
 			 struct apk_package *pkg)
 {
 	struct apk_istream *is;
-	char infile[256];
-	char outfile[256];
+	char pkgfile[PATH_MAX], url[PATH_MAX];
 	int i, r, fd;
 
-	if (!(fctx->flags & FETCH_STDOUT)) {
-		struct stat st;
+	apk_pkg_format_plain(pkg, APK_BLOB_BUF(pkgfile));
 
-		snprintf(outfile, sizeof(outfile), "%s/%s-%s.apk",
-			 fctx->outdir ? fctx->outdir : ".",
-			 pkg->name->name, pkg->version);
+	if (!(fctx->flags & FETCH_STDOUT)) {
+		struct apk_file_info fi;
 
-		if (lstat(outfile, &st) == 0 && st.st_size == pkg->size)
+		if (apk_file_get_info(fctx->outdir_fd, pkgfile,
+				      APK_CHECKSUM_NONE, &fi) == 0 &&
+		    fi.size == pkg->size)
 			return 0;
 	}
-	apk_message("Downloading %s-%s", pkg->name->name, pkg->version);
 
+	apk_message("Downloading %s-%s", pkg->name->name, pkg->version);
 	for (i = 0; i < APK_MAX_REPOS; i++)
 		if (pkg->repos & BIT(i))
 			break;
@@ -122,31 +122,30 @@ static int fetch_package(struct fetch_ctx *fctx,
 	if (apk_flags & APK_SIMULATE)
 		return 0;
 
-	snprintf(infile, sizeof(infile), "%s/%s-%s.apk",
-		 db->repos[i].url, pkg->name->name, pkg->version);
+	snprintf(url, sizeof(url), "%s%s%s", db->repos[i].url,
+		 db->repos[i].url[strlen(db->repos[i].url)-1] == '/' ? "" : "/",
+		 pkgfile);
 
 	if (fctx->flags & FETCH_STDOUT) {
 		fd = STDOUT_FILENO;
 	} else {
-		if ((fctx->flags & FETCH_LINK) && apk_url_local_file(infile)) {
-			char real_infile[256];
-			int n;
-			n = readlink(infile, real_infile, sizeof(real_infile));
-			if (n > 0 && n < sizeof(real_infile))
-				real_infile[n] = '\0';
-			if (link(real_infile, outfile) == 0)
+		if ((fctx->flags & FETCH_LINK) && apk_url_local_file(url)) {
+			if (linkat(AT_FDCWD, url,
+				   fctx->outdir_fd, pkgfile,
+				   AT_SYMLINK_FOLLOW) == 0)
 				return 0;
 		}
-		fd = creat(outfile, 0644);
+		fd = openat(fctx->outdir_fd, pkgfile,
+			    O_CREAT|O_RDWR|O_TRUNC, 0644);
 		if (fd < 0) {
-			apk_error("%s: %s", outfile, strerror(errno));
+			apk_error("%s: %s", pkgfile, strerror(errno));
 			return -1;
 		}
 	}
 
-	is = apk_istream_from_url(infile);
+	is = apk_istream_from_url(url);
 	if (is == NULL) {
-		apk_error("Unable to download '%s'", infile);
+		apk_error("Unable to download '%s'", url);
 		return -1;
 	}
 
@@ -155,8 +154,8 @@ static int fetch_package(struct fetch_ctx *fctx,
 	if (fd != STDOUT_FILENO)
 		close(fd);
 	if (r != pkg->size) {
-		apk_error("Unable to download '%s'", infile);
-		unlink(outfile);
+		apk_error("Unable to download '%s'", url);
+		unlinkat(fctx->outdir_fd, pkgfile, 0);
 		return -1;
 	}
 
@@ -169,6 +168,9 @@ static int fetch_main(void *ctx, int argc, char **argv)
 	struct apk_database db;
 	int i, j, r;
 
+	if (fctx->outdir_fd == 0)
+		fctx->outdir_fd = AT_FDCWD;
+
 	if ((argc > 0) && (strcmp(argv[0], "coffee") == 0)) {
 		if (apk_flags & APK_FORCE)
 			return cup();
diff --git a/src/index.c b/src/index.c
index c27d020..4ef8aef 100644
--- a/src/index.c
+++ b/src/index.c
@@ -55,7 +55,7 @@ static int index_read_file(struct apk_database *db, struct index_ctx *ictx)
 
 	if (ictx->index == NULL)
 		return 0;
-	if (apk_file_get_info(ictx->index, APK_CHECKSUM_NONE, &fi) < 0)
+	if (apk_file_get_info(AT_FDCWD, ictx->index, APK_CHECKSUM_NONE, &fi) < 0)
 		return -1;
 	ictx->index_mtime = fi.mtime;
 
@@ -107,7 +107,7 @@ static int index_main(void *ctx, int argc, char **argv)
 	}
 
 	for (i = 0; i < argc; i++) {
-		if (apk_file_get_info(argv[i], APK_CHECKSUM_NONE, &fi) < 0) {
+		if (apk_file_get_info(AT_FDCWD, argv[i], APK_CHECKSUM_NONE, &fi) < 0) {
 			apk_warning("File '%s' is unaccessible", argv[i]);
 			continue;
 		}
@@ -154,7 +154,7 @@ static int index_main(void *ctx, int argc, char **argv)
 
 		if (!found) {
 			struct apk_sign_ctx sctx;
-			apk_sign_ctx_init(&sctx, ictx->method, NULL);
+			apk_sign_ctx_init(&sctx, ictx->method, NULL, db.keys_fd);
 			if (apk_pkg_read(&db, argv[i], &sctx, NULL) == 0)
 				newpkgs++;
 			apk_sign_ctx_free(&sctx);
@@ -171,7 +171,7 @@ static int index_main(void *ctx, int argc, char **argv)
 	}
 
 	if (ictx->output != NULL)
-		os = apk_ostream_to_file(ictx->output, 0644);
+		os = apk_ostream_to_file(AT_FDCWD, ictx->output, 0644);
 	else
 		os = apk_ostream_to_fd(STDOUT_FILENO);
 	if (ictx->method == APK_SIGN_GENERATE) {
diff --git a/src/io.c b/src/io.c
index 3929ba1..a6cdd4d 100644
--- a/src/io.c
+++ b/src/io.c
@@ -77,11 +77,11 @@ struct apk_istream *apk_istream_from_fd(int fd)
 	return &fis->is;
 }
 
-struct apk_istream *apk_istream_from_file(const char *file)
+struct apk_istream *apk_istream_from_file(int atfd, const char *file)
 {
 	int fd;
 
-	fd = open(file, O_RDONLY);
+	fd = openat(atfd, file, O_RDONLY);
 	if (fd < 0)
 		return NULL;
 
@@ -342,11 +342,11 @@ struct apk_bstream *apk_bstream_from_fd(int fd)
 	return apk_bstream_from_istream(apk_istream_from_fd(fd));
 }
 
-struct apk_bstream *apk_bstream_from_file(const char *file)
+struct apk_bstream *apk_bstream_from_file(int atfd, const char *file)
 {
 	int fd;
 
-	fd = open(file, O_RDONLY);
+	fd = openat(atfd, file, O_RDONLY);
 	if (fd < 0)
 		return NULL;
 
@@ -387,12 +387,13 @@ static void tee_close(void *stream, size_t *size)
 	free(tbs);
 }
 
-struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, const char *to)
+struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to)
 {
 	struct apk_tee_bstream *tbs;
 	int fd;
 
-	fd = creat(to, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	fd = openat(atfd, to, O_CREAT | O_RDWR | O_TRUNC,
+		    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 	if (fd < 0)
 		return NULL;
 
@@ -433,13 +434,13 @@ apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
 	return APK_BLOB_PTR_LEN(ptr, rsize);
 }
 
-apk_blob_t apk_blob_from_file(const char *file)
+apk_blob_t apk_blob_from_file(int atfd, const char *file)
 {
 	int fd;
 	struct stat st;
 	char *buf;
 
-	fd = open(file, O_RDONLY);
+	fd = openat(atfd, file, O_RDONLY);
 	if (fd < 0)
 		return APK_BLOB_NULL;
 
@@ -462,12 +463,13 @@ err_fd:
 	return APK_BLOB_NULL;
 }
 
-int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *fi)
+int apk_file_get_info(int atfd, const char *filename, int checksum,
+		      struct apk_file_info *fi)
 {
-	struct stat st;
+	struct stat64 st;
 	struct apk_bstream *bs;
 
-	if (lstat(filename, &st) != 0)
+	if (fstatat64(atfd, filename, &st, AT_SYMLINK_NOFOLLOW) != 0)
 		return -errno;
 
 	*fi = (struct apk_file_info) {
@@ -482,7 +484,7 @@ int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *
 	if (checksum == APK_CHECKSUM_NONE)
 		return 0;
 
-	bs = apk_bstream_from_file(filename);
+	bs = apk_bstream_from_file(atfd, filename);
 	if (bs != NULL) {
 		EVP_MD_CTX mdctx;
 		apk_blob_t blob;
@@ -501,9 +503,9 @@ int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *
 	return 0;
 }
 
-struct apk_istream *apk_istream_from_file_gz(const char *file)
+struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file)
 {
-	return apk_bstream_gunzip(apk_bstream_from_file(file));
+	return apk_bstream_gunzip(apk_bstream_from_file(atfd, file));
 }
 
 struct apk_fd_ostream {
@@ -593,11 +595,11 @@ struct apk_ostream *apk_ostream_to_fd(int fd)
 	return &fos->os;
 }
 
-struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode)
+struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode)
 {
 	int fd;
 
-	fd = creat(file, mode);
+	fd = openat(atfd, file, O_CREAT | O_RDWR | O_TRUNC, mode);
 	if (fd < 0)
 		return NULL;
 
diff --git a/src/package.c b/src/package.c
index 43ce646..152edf6 100644
--- a/src/package.c
+++ b/src/package.c
@@ -28,6 +28,29 @@
 #include "apk_database.h"
 #include "apk_state.h"
 
+void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to)
+{
+	/* pkgname-1.0.apk */
+	apk_blob_push_blob(&to, APK_BLOB_STR(pkg->name->name));
+	apk_blob_push_blob(&to, APK_BLOB_STR("-"));
+	apk_blob_push_blob(&to, APK_BLOB_STR(pkg->version));
+	apk_blob_push_blob(&to, APK_BLOB_STR(".apk"));
+	apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
+}
+
+void apk_pkg_format_cache(struct apk_package *pkg, apk_blob_t to)
+{
+	/* pkgname-1.0_alpha1.12345678.apk */
+	apk_blob_push_blob(&to, APK_BLOB_STR(pkg->name->name));
+	apk_blob_push_blob(&to, APK_BLOB_STR("-"));
+	apk_blob_push_blob(&to, APK_BLOB_STR(pkg->version));
+	apk_blob_push_blob(&to, APK_BLOB_STR("."));
+	apk_blob_push_hexdump(&to, APK_BLOB_PTR_LEN((char *) pkg->csum.data,
+						    APK_CACHE_CSUM_BYTES));
+	apk_blob_push_blob(&to, APK_BLOB_STR(".apk"));
+	apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
+}
+
 struct apk_package *apk_pkg_new(void)
 {
 	struct apk_package *pkg;
@@ -56,6 +79,9 @@ int apk_pkg_parse_name(apk_blob_t apkname,
 		if (++dash >= 2)
 			return -1;
 	}
+	if (i < 0)
+		return -1;
+
 	if (name != NULL)
 		*name = APK_BLOB_PTR_LEN(apkname.ptr, i);
 	if (version != NULL)
@@ -282,9 +308,10 @@ int apk_script_type(const char *name)
 }
 
 void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
-		       struct apk_checksum *identity)
+		       struct apk_checksum *identity, int keys_fd)
 {
 	memset(ctx, 0, sizeof(struct apk_sign_ctx));
+	ctx->keys_fd = keys_fd;
 	ctx->action = action;
 	switch (action) {
 	case APK_SIGN_NONE:
@@ -359,14 +386,19 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
 	    ctx->signature.pkey != NULL)
 		return 0;
 
+	if (ctx->keys_fd < 0)
+		return 0;
+
 	if (strncmp(&fi->name[6], "RSA.", 4) == 0 ||
 	    strncmp(&fi->name[6], "DSA.", 4) == 0) {
-		char file[256];
-	        BIO *bio = BIO_new(BIO_s_file());
-		snprintf(file, sizeof(file), "/etc/apk/keys/%s", &fi->name[10]);
-		if (BIO_read_filename(bio, file) > 0)
-			ctx->signature.pkey =
-				PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+		int fd = openat(ctx->keys_fd, &fi->name[10], O_RDONLY);
+	        BIO *bio;
+
+		if (fd < 0)
+			return 0;
+
+		bio  = BIO_new_fp(fdopen(fd, "r"), 0);
+		ctx->signature.pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
 		if (ctx->signature.pkey != NULL) {
 			if (fi->name[6] == 'R')
 				ctx->md = EVP_sha1();
@@ -690,12 +722,9 @@ int apk_pkg_read(struct apk_database *db, const char *file,
 	struct apk_file_info fi;
 	struct apk_bstream *bs;
 	struct apk_istream *tar;
-	char realfile[PATH_MAX];
 	int r;
 
-	if (realpath(file, realfile) < 0)
-		return -errno;
-	r = apk_file_get_info(realfile, APK_CHECKSUM_NONE, &fi);
+	r = apk_file_get_info(AT_FDCWD, file, APK_CHECKSUM_NONE, &fi);
 	if (r != 0)
 		return r;
 
@@ -705,7 +734,7 @@ int apk_pkg_read(struct apk_database *db, const char *file,
 	r = -ENOMEM;
 	if (ctx.pkg == NULL)
 		goto err;
-	bs = apk_bstream_from_file(realfile);
+	bs = apk_bstream_from_file(AT_FDCWD, file);
 	if (bs == NULL)
 		goto err;
 
@@ -723,7 +752,7 @@ int apk_pkg_read(struct apk_database *db, const char *file,
 	}
 	if (sctx->action != APK_SIGN_VERIFY)
 		ctx.pkg->csum = sctx->identity;
-	ctx.pkg->filename = strdup(realfile);
+	ctx.pkg->filename = strdup(file);
 
 	ctx.pkg = apk_db_pkg_add(db, ctx.pkg);
 	if (pkg != NULL)
@@ -814,18 +843,17 @@ int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
 	struct hlist_node *c;
 	int fd, status;
 	pid_t pid;
-	char fn[1024];
+	char fn[PATH_MAX];
 
-	fchdir(root_fd);
 	hlist_for_each_entry(script, c, &pkg->scripts, script_list) {
 		if (script->type != type)
 			continue;
 
-		snprintf(fn, sizeof(fn),
-			"tmp/%s-%s.%s",
+		snprintf(fn, sizeof(fn), "tmp/%s-%s.%s",
 			pkg->name->name, pkg->version,
 			apk_script_types[type]);
-		fd = creat(fn, 0777);
+
+		fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0777);
 		if (fd < 0)
 			return fd;
 		write(fd, script->script, script->size);
@@ -837,6 +865,7 @@ int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
 		if (pid == -1)
 			return -1;
 		if (pid == 0) {
+			fchdir(root_fd);
 			if (chroot(".") < 0) {
 				apk_error("chroot: %s", strerror(errno));
 			} else {
@@ -846,7 +875,7 @@ int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
 			exit(1);
 		}
 		waitpid(pid, &status, 0);
-		unlink(fn);
+		unlinkat(root_fd, fn, 0);
 		if (WIFEXITED(status))
 			return WEXITSTATUS(status);
 		return -1;
diff --git a/src/state.c b/src/state.c
index 16acfba..c539b02 100644
--- a/src/state.c
+++ b/src/state.c
@@ -711,7 +711,7 @@ int apk_state_commit(struct apk_state *state,
 	if (apk_flags & APK_PROGRESS)
 		apk_draw_progress(20, 1);
 
-	if (!(apk_flags & APK_SIMULATE) && prog.done.packages != 0)
+	if (!(apk_flags & APK_SIMULATE))
 		apk_db_write_config(db);
 
 	if (r == 0)
diff --git a/src/url.c b/src/url.c
index e09ec4c..be5e285 100644
--- a/src/url.c
+++ b/src/url.c
@@ -11,6 +11,7 @@
 
 #include <stdio.h>
 #include <fcntl.h>
+#include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/wait.h>
@@ -61,7 +62,7 @@ static int fork_wget(const char *url)
 struct apk_istream *apk_istream_from_url(const char *url)
 {
 	if (apk_url_local_file(url) != NULL)
-		return apk_istream_from_file(apk_url_local_file(url));
+		return apk_istream_from_file(AT_FDCWD, apk_url_local_file(url));
 
 	return apk_istream_from_fd(fork_wget(url));
 }
@@ -74,16 +75,19 @@ struct apk_istream *apk_istream_from_url_gz(const char *file)
 struct apk_bstream *apk_bstream_from_url(const char *url)
 {
 	if (apk_url_local_file(url))
-		return apk_bstream_from_file(url);
+		return apk_bstream_from_file(AT_FDCWD, url);
 
 	return apk_bstream_from_fd(fork_wget(url));
 }
 
-int apk_url_download(const char *url, const char *file)
+int apk_url_download(const char *url, int atfd, const char *file)
 {
 	pid_t pid;
-	int status;
-	char tmp[256];
+	int status, fd;
+
+	fd = openat(atfd, file, O_CREAT|O_RDWR|O_TRUNC, 0644);
+	if (fd < 0)
+		return -errno;
 
 	pid = fork();
 	if (pid == -1)
@@ -92,15 +96,14 @@ int apk_url_download(const char *url, const char *file)
 	if (pid == 0) {
 		setsid();
 		dup2(open("/dev/null", O_RDONLY), STDIN_FILENO);
-		snprintf(tmp, sizeof(tmp), "%s.backup", file);
-		rename(file, tmp);
-		execlp("wget", "wget", "-q", "-O", file, url, NULL);
+		dup2(fd, STDOUT_FILENO);
+		execlp("wget", "wget", "-q", "-O", "-", url, NULL);
 		exit(0);
 	}
 
 	waitpid(pid, &status, 0);
 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-		unlink(file);
+		unlinkat(atfd, file, 0);
 		return -1;
 	}
 
diff --git a/src/verify.c b/src/verify.c
index 82e9b2d..dc9ddb6 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -10,6 +10,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <unistd.h>
 
 #include "apk_applet.h"
@@ -19,12 +20,17 @@ static int verify_main(void *ctx, int argc, char **argv)
 {
 	struct apk_sign_ctx sctx;
 	struct apk_istream *is;
+	struct apk_database db;
 	int i, r, ok, rc = 0;
 
 	apk_flags |= APK_ALLOW_UNTRUSTED;
+	r = apk_db_open(&db, apk_root, APK_OPENF_READ | APK_OPENF_NO_STATE);
+	if (r != 0)
+		return r;
+
 	for (i = 0; i < argc; i++) {
-		apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
-		is = apk_bstream_gunzip_mpart(apk_bstream_from_file(argv[i]),
+		apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db.keys_fd);
+		is = apk_bstream_gunzip_mpart(apk_bstream_from_file(AT_FDCWD, argv[i]),
 					      apk_sign_ctx_mpart_cb, &sctx);
 		if (is == NULL) {
 			apk_error("%s: %s", strerror(errno), argv[i]);
@@ -43,6 +49,7 @@ static int verify_main(void *ctx, int argc, char **argv)
 			rc++;
 		apk_sign_ctx_free(&sctx);
 	}
+	apk_db_close(&db);
 
 	return rc;
 }
-- 
cgit v1.2.3-70-g09d2