summaryrefslogtreecommitdiff
path: root/src/database.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/database.c')
-rw-r--r--src/database.c208
1 files changed, 74 insertions, 134 deletions
diff --git a/src/database.c b/src/database.c
index f5c8d8c..a3a5800 100644
--- a/src/database.c
+++ b/src/database.c
@@ -37,6 +37,7 @@
#include "apk_openssl.h"
#include "apk_tar.h"
#include "apk_adb.h"
+#include "apk_fs.h"
static const apk_spn_match_def apk_spn_repo_separators = {
[1] = (1<<1) /* tab */,
@@ -83,6 +84,11 @@ struct install_ctx {
struct hlist_node **file_diri_node;
};
+static apk_blob_t apk_pkg_ctx(struct apk_package *pkg)
+{
+ return APK_BLOB_PTR_LEN(pkg->name->name, strlen(pkg->name->name)+1);
+}
+
static apk_blob_t pkg_name_get_key(apk_hash_item item)
{
return APK_BLOB_STR(((struct apk_name *) item)->name);
@@ -244,23 +250,21 @@ static struct apk_db_acl *apk_db_acl_atomize_digest(struct apk_database *db, mod
static void apk_db_dir_prepare(struct apk_database *db, struct apk_db_dir *dir, mode_t newmode)
{
- struct stat st;
+ struct apk_fsdir d;
if (dir->namelen == 0) return;
if (dir->created) return;
- if (fstatat(db->root_fd, dir->name, &st, AT_SYMLINK_NOFOLLOW) == 0) {
- /* If directory exists and stats match what we expect,
- * then we can allow auto updating the permissions */
- dir->created = 1;
- dir->update_permissions |=
- (st.st_mode & 07777) == (dir->mode & 07777) &&
- st.st_uid == dir->uid && st.st_gid == dir->gid;
- } else if (newmode) {
+ apk_fsdir_get(&d, APK_BLOB_PTR_LEN(dir->name, dir->namelen), db->ctx, APK_BLOB_NULL);
+ switch (apk_fsdir_check(&d, dir->mode, dir->uid, dir->gid)) {
+ default:
if (!(db->ctx->flags & APK_SIMULATE))
- mkdirat(db->root_fd, dir->name, newmode);
- dir->created = 1;
+ apk_fsdir_create(&d, dir->mode);
+ case 0:
dir->update_permissions = 1;
+ case APK_FS_DIR_MODIFIED:
+ dir->created = 1;
+ break;
}
}
@@ -272,9 +276,11 @@ void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir, int rmdir
if (dir->namelen != 0) {
if (rmdir_mode == APK_DIR_REMOVE) {
dir->modified = 1;
- if (!(db->ctx->flags & APK_SIMULATE) &&
- unlinkat(db->root_fd, dir->name, AT_REMOVEDIR) != 0)
- ;
+ if (!(db->ctx->flags & APK_SIMULATE)) {
+ struct apk_fsdir d;
+ apk_fsdir_get(&d, APK_BLOB_PTR_LEN(dir->name, dir->namelen), db->ctx, APK_BLOB_NULL);
+ apk_fsdir_delete(&d);
+ }
}
apk_db_dir_unref(db, dir->parent, rmdir_mode);
dir->parent = NULL;
@@ -1953,20 +1959,15 @@ static int update_permissions(apk_hash_item item, void *pctx)
struct update_permissions_ctx *ctx = pctx;
struct apk_database *db = ctx->db;
struct apk_db_dir *dir = (struct apk_db_dir *) item;
- struct stat st;
- int r;
+ struct apk_fsdir d;
if (dir->refs == 0) return 0;
if (!dir->update_permissions) return 0;
dir->seen = 0;
- r = fstatat(db->root_fd, dir->name, &st, AT_SYMLINK_NOFOLLOW);
- if (r < 0 || (st.st_mode & 07777) != (dir->mode & 07777))
- if (fchmodat(db->root_fd, dir->name, dir->mode, 0) < 0)
- ctx->errors++;
- if (r < 0 || st.st_uid != dir->uid || st.st_gid != dir->gid)
- if (fchownat(db->root_fd, dir->name, dir->uid, dir->gid, 0) < 0)
- ctx->errors++;
+ apk_fsdir_get(&d, APK_BLOB_PTR_LEN(dir->name, dir->namelen), db->ctx, APK_BLOB_NULL);
+ if (apk_fsdir_update_perms(&d, dir->mode, dir->uid, dir->gid) != 0)
+ ctx->errors++;
return 0;
}
@@ -2330,37 +2331,6 @@ static struct apk_db_dir_instance *apk_db_install_directory_entry(struct install
return diri;
}
-#define TMPNAME_MAX (PATH_MAX + 64)
-
-static const char *format_tmpname(struct apk_package *pkg, struct apk_db_file *f, char tmpname[static TMPNAME_MAX])
-{
- struct apk_digest_ctx dctx;
- struct apk_digest d;
- apk_blob_t b = APK_BLOB_PTR_LEN(tmpname, TMPNAME_MAX);
-
- if (!f) return NULL;
-
- if (apk_digest_ctx_init(&dctx, APK_DIGEST_SHA256) != 0) return NULL;
-
- apk_digest_ctx_update(&dctx, pkg->name->name, strlen(pkg->name->name) + 1);
- apk_digest_ctx_update(&dctx, f->diri->dir->name, f->diri->dir->namelen);
- apk_digest_ctx_update(&dctx, "/", 1);
- apk_digest_ctx_update(&dctx, f->name, f->namelen);
- apk_digest_ctx_final(&dctx, &d);
- apk_digest_ctx_free(&dctx);
-
- apk_blob_push_blob(&b, APK_BLOB_PTR_LEN(f->diri->dir->name, f->diri->dir->namelen));
- if (f->diri->dir->namelen > 0) {
- apk_blob_push_blob(&b, APK_BLOB_STR("/.apk."));
- } else {
- apk_blob_push_blob(&b, APK_BLOB_STR(".apk."));
- }
- apk_blob_push_hexdump(&b, APK_BLOB_PTR_LEN((char *)d.data, 24));
- apk_blob_push_blob(&b, APK_BLOB_PTR_LEN("", 1));
-
- return tmpname;
-}
-
static int contains_control_character(const char *str)
{
for (const uint8_t *p = (const uint8_t *) str; *p; p++) {
@@ -2386,7 +2356,7 @@ static int apk_db_install_v3meta(struct apk_extract_ctx *ectx, struct adb_obj *p
struct adb_obj triggers, pkginfo, obj;
int i;
- apk_pkg_from_adb(db, ctx->pkg, pkg);
+ // Extract the information not available in index
adb_ro_obj(pkg, ADBI_PKG_PKGINFO, &pkginfo);
apk_deps_from_adb(&ipkg->replaces, db, adb_ro_obj(&pkginfo, ADBI_PI_REPLACES, &obj));
ipkg->replaces_priority = adb_ro_int(&pkginfo, ADBI_PI_PRIORITY);
@@ -2424,7 +2394,6 @@ static int apk_db_install_file(struct apk_extract_ctx *ectx, const struct apk_fi
struct apk_db_dir_instance *diri = ctx->diri;
struct apk_db_file *file, *link_target_file = NULL;
int ret = 0, r;
- char tmpname_file[TMPNAME_MAX], tmpname_link_target[TMPNAME_MAX];
apk_db_run_pending_script(ctx);
if (ae->name[0] == '.') return 0;
@@ -2440,13 +2409,6 @@ static int apk_db_install_file(struct apk_extract_ctx *ectx, const struct apk_fi
return 0;
}
- if (ae->uvol_name) {
- apk_warn(out, PKG_VER_FMT": %s: uvol not supported yet",
- PKG_VER_PRINTF(pkg), ae->name);
- ipkg->broken_files = 1;
- return APK_EXTRACT_SKIP_FILE;
- }
-
/* Installable entry */
ctx->current_file_size = apk_calc_installed_size(ae->size);
if (!S_ISDIR(ae->mode)) {
@@ -2563,12 +2525,7 @@ static int apk_db_install_file(struct apk_extract_ctx *ectx, const struct apk_fi
/* Extract the file with temporary name */
file->acl = apk_db_acl_atomize_digest(db, ae->mode, ae->uid, ae->gid, &ae->xattr_digest);
- r = apk_extract_file(
- db->root_fd, ae,
- format_tmpname(pkg, file, tmpname_file),
- format_tmpname(pkg, link_target_file, tmpname_link_target),
- is, extract_cb, ctx, db->extract_flags, ac);
-
+ r = apk_fs_extract(ac, ae, is, extract_cb, ctx, db->extract_flags, apk_pkg_ctx(pkg));
switch (r) {
case 0:
/* Hardlinks need special care for checksum */
@@ -2596,6 +2553,10 @@ static int apk_db_install_file(struct apk_extract_ctx *ectx, const struct apk_fi
ctx->missing_checksum = 1;
}
break;
+ case -APKE_UVOL_ROOT:
+ case -APKE_UVOL_NOT_AVAILABLE:
+ ipkg->broken_files = 1;
+ break;
case -ENOTSUP:
ipkg->broken_xattr = 1;
break;
@@ -2638,22 +2599,20 @@ static void apk_db_purge_pkg(struct apk_database *db,
struct apk_db_dir_instance *diri;
struct apk_db_file *file;
struct apk_db_file_hash_key key;
- struct apk_file_info fi;
+ struct apk_fsdir d;
+ struct apk_digest dgst;
struct hlist_node *dc, *dn, *fc, *fn;
unsigned long hash;
- char name[TMPNAME_MAX];
+ int ctrl = is_installed ? APK_FS_CTRL_DELETE : APK_FS_CTRL_CANCEL;
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
+ apk_blob_t dirname = APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen);
if (is_installed) diri->dir->modified = 1;
+ apk_fsdir_get(&d, dirname, db->ctx, apk_pkg_ctx(ipkg->pkg));
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
- if (is_installed)
- snprintf(name, sizeof name, DIR_FILE_FMT, DIR_FILE_PRINTF(diri->dir, file));
- else
- format_tmpname(ipkg->pkg, file, name);
-
key = (struct apk_db_file_hash_key) {
- .dirname = APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen),
+ .dirname = dirname,
.filename = APK_BLOB_PTR_LEN(file->name, file->namelen),
};
hash = apk_blob_hash_seed(key.filename, diri->dir->hash);
@@ -2661,10 +2620,11 @@ static void apk_db_purge_pkg(struct apk_database *db,
(diri->dir->protect_mode == APK_PROTECT_NONE) ||
(db->ctx->flags & APK_PURGE) ||
(file->csum.type != APK_CHECKSUM_NONE &&
- apk_fileinfo_get(db->root_fd, name, APK_FI_NOFOLLOW | APK_FI_DIGEST(apk_dbf_digest(file)), &fi, &db->atoms) == 0 &&
- apk_digest_cmp_csum(&fi.digest, &file->csum) == 0))
- unlinkat(db->root_fd, name, 0);
- apk_dbg2(out, "%s", name);
+ apk_fsdir_file_digest(&d, key.filename, apk_dbf_digest(file), &dgst) == 0 &&
+ apk_digest_cmp_csum(&dgst, &file->csum) == 0))
+ apk_fsdir_file_control(&d, key.filename, ctrl);
+
+ apk_dbg2(out, DIR_FILE_FMT, DIR_FILE_PRINTF(diri->dir, file));
__hlist_del(fc, &diri->owned_files.first);
if (is_installed) {
apk_hash_delete_hashed(&db->installed.files, APK_BLOB_BUF(&key), hash);
@@ -2685,22 +2645,22 @@ static void apk_db_migrate_files(struct apk_database *db,
struct apk_db_dir *dir;
struct apk_db_file *file, *ofile;
struct apk_db_file_hash_key key;
- struct apk_file_info fi;
struct hlist_node *dc, *dn, *fc, *fn;
+ struct apk_fsdir d;
+ struct apk_digest dgst;
unsigned long hash;
- char name[PATH_MAX], tmpname[TMPNAME_MAX];
- int cstype, r;
+ apk_blob_t dirname;
+ int r, ctrl;
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
dir = diri->dir;
dir->modified = 1;
+ dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen);
+ apk_fsdir_get(&d, dirname, db->ctx, apk_pkg_ctx(ipkg->pkg));
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
- snprintf(name, sizeof(name), DIR_FILE_FMT, DIR_FILE_PRINTF(diri->dir, file));
- format_tmpname(ipkg->pkg, file, tmpname);
-
key = (struct apk_db_file_hash_key) {
- .dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
+ .dirname = dirname,
.filename = APK_BLOB_PTR_LEN(file->name, file->namelen),
};
@@ -2710,61 +2670,41 @@ static void apk_db_migrate_files(struct apk_database *db,
ofile = (struct apk_db_file *) apk_hash_get_hashed(
&db->installed.files, APK_BLOB_BUF(&key), hash);
- /* We want to compare checksums only if one exists
- * in db, and the file is in a protected path */
- cstype = APK_CHECKSUM_NONE;
- if (ofile != NULL && diri->dir->protect_mode != APK_PROTECT_NONE)
- cstype = APK_FI_DIGEST(apk_dbf_digest(ofile));
- cstype |= APK_FI_NOFOLLOW;
-
- r = apk_fileinfo_get(db->root_fd, name, cstype, &fi, &db->atoms);
+ ctrl = APK_FS_CTRL_COMMIT;
if (ofile && ofile->diri->pkg->name == NULL) {
- /* File was from overlay, delete the
- * packages version */
- unlinkat(db->root_fd, tmpname, 0);
+ // File was from overlay, delete the package's version
+ ctrl = APK_FS_CTRL_CANCEL;
} else if ((diri->dir->protect_mode != APK_PROTECT_NONE) &&
- (r == 0) &&
- (ofile == NULL ||
- ofile->csum.type == APK_CHECKSUM_NONE ||
- apk_digest_cmp_csum(&fi.digest, &ofile->csum) != 0)) {
- /* Protected directory, with file without
- * db entry, or local modifications.
- *
- * Delete the apk-new if it's identical with the
- * existing file */
- if (ofile == NULL ||
- ofile->csum.type != file->csum.type)
- apk_fileinfo_get(db->root_fd, name,
- APK_FI_NOFOLLOW |APK_FI_DIGEST(apk_dbf_digest(file)),
- &fi, &db->atoms);
+ (!ofile || ofile->csum.type == APK_CHECKSUM_NONE ||
+ (apk_fsdir_file_digest(&d, key.filename, apk_dbf_digest(ofile), &dgst) == 0 &&
+ apk_digest_cmp_csum(&dgst, &ofile->csum) != 0))) {
+ // Protected directory, and a file without db entry
+ // or with local modifications. Keep the filesystem file.
+ // Determine if the package's file should be kept as .apk-new
if ((db->ctx->flags & APK_CLEAN_PROTECTED) ||
(file->csum.type != APK_CHECKSUM_NONE &&
- apk_digest_cmp_csum(&fi.digest, &file->csum) == 0)) {
- unlinkat(db->root_fd, tmpname, 0);
+ (apk_fsdir_file_digest(&d, key.filename, apk_dbf_digest(file), &dgst) == 0 &&
+ apk_digest_cmp_csum(&dgst, &file->csum) == 0))) {
+ // No .apk-new files allowed, or the file on disk has the same
+ // hash as the file from new package. Keep the on disk one.
+ ctrl = APK_FS_CTRL_CANCEL;
} else {
- snprintf(name, sizeof name,
- DIR_FILE_FMT ".apk-new",
- DIR_FILE_PRINTF(diri->dir, file));
- if (renameat(db->root_fd, tmpname,
- db->root_fd, name) != 0) {
- apk_err(out, PKG_VER_FMT": failed to rename %s to %s.",
- PKG_VER_PRINTF(ipkg->pkg),
- tmpname, name);
- ipkg->broken_files = 1;
- }
+ // All files difference. Use the package's file as .apk-new.
+ ctrl = APK_FS_CTRL_APKNEW;
}
+ }
- } else {
- /* Overwrite the old file */
- if (renameat(db->root_fd, tmpname,
- db->root_fd, name) != 0) {
- apk_err(out, PKG_VER_FMT": failed to rename %s to %s.",
- PKG_VER_PRINTF(ipkg->pkg), tmpname, name);
- ipkg->broken_files = 1;
- }
+ // Commit changes
+ r = apk_fsdir_file_control(&d, key.filename, ctrl);
+ if (r < 0) {
+ apk_err(out, PKG_VER_FMT": failed to commit " DIR_FILE_FMT ": %s",
+ PKG_VER_PRINTF(ipkg->pkg),
+ DIR_FILE_PRINTF(diri->dir, file),
+ apk_error_str(r));
+ ipkg->broken_files = 1;
}
- /* Claim ownership of the file in db */
+ // Claim ownership of the file in db
if (ofile != file) {
if (ofile != NULL) {
hlist_del(&ofile->diri_files_list,