Newer
Older
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 (dbopts->open_flags & APK_OPENF_WRITE) {
db->lock_fd = openat(db->root_fd, "var/lib/apk/lock",
O_CREAT | O_RDWR, 0400);
if (db->lock_fd < 0 && errno == ENOENT &&
(dbopts->open_flags & APK_OPENF_CREATE)) {
r = apk_db_create(db);
if (r != 0) {
msg = "Unable to create database";
goto ret_r;
}
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) {
msg = "Unable to lock database";
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)
alarm(0);
sigaction(SIGALRM, &old_sa, NULL);
} else
goto ret_errno;
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,
dbopts->keys_dir ?: "etc/apk/keys",
O_RDONLY);
r = apk_db_read_state(db, dbopts->open_flags);
if (r == -ENOENT && (dbopts->open_flags & APK_OPENF_CREATE)) {
msg = "Unable to create database";
r = apk_db_read_state(db, dbopts->open_flags);
}
if (r != 0) {
msg = "Unable to read database state";
goto ret_r;
if (!(dbopts->open_flags & APK_OPENF_NO_REPOS)) {
list_for_each_entry(repo, &dbopts->repository_list, list) {
r = apk_db_add_repository(db, APK_BLOB_STR(repo->url));
rr = r ?: rr;
}
blob = apk_blob_from_file(
db->root_fd,
dbopts->repositories_file ?: "etc/apk/repositories");
if (!APK_BLOB_IS_NULL(blob)) {
r = apk_blob_for_each_segment(
blob, "\n",
apk_db_add_repository, db);
rr = r ?: rr;
free(blob.ptr);
}
if (apk_flags & APK_UPDATE_CACHE)
apk_db_index_write_nr_cache(db);
if (rr != 0) {
r = rr;
goto ret_r;
}
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 ((apk_flags & APK_SIMULATE) || db->root == NULL)
if (db->lock_fd == 0) {
apk_error("Refusing to write db without write lock!");
return -1;
}
os = apk_ostream_to_file(db->root_fd,
"var/lib/apk/world",
"var/lib/apk/world.new",
0644);
return -1;
apk_deps_write(db->world, os);
os->write(os, "\n", 1);
r = os->close(os);
if (r < 0)
return r;
os = apk_ostream_to_file(db->root_fd,
"var/lib/apk/installed",
"var/lib/apk/installed.new",
0644);
return -1;
r = os->close(os);
if (r < 0)
return r;
os = apk_ostream_to_file(db->root_fd,
"var/lib/apk/scripts.tar",
"var/lib/apk/scripts.tar.new",
0644);
return -1;
r = os->close(os);
if (r < 0)
return r;
unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
apk_db_index_write_nr_cache(db);
os = apk_ostream_to_file(db->root_fd,
"var/lib/apk/triggers",
"var/lib/apk/triggers.new",
0644);
if (os == NULL)
return -1;
apk_db_triggers_write(db, os);
r = os->close(os);
if (r < 0)
return r;
return 0;
}
void apk_db_close(struct apk_database *db)
{
struct apk_installed_package *ipkg;
struct hlist_node *dc, *dn;
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->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->keys_fd)
close(db->keys_fd);
if (db->cachetmp_fd)
close(db->cachetmp_fd);
if (db->cache_fd)
close(db->cache_fd);
if (db->lock_fd)
close(db->lock_fd);
if (db->root != NULL)
free(db->root);
}
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
static int fire_triggers(apk_hash_item item, void *ctx)
{
struct apk_database *db = (struct apk_database *) ctx;
struct apk_db_dir *dbd = (struct apk_db_dir *) item;
struct apk_installed_package *ipkg;
int i;
list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) {
if (((ipkg->flags & APK_IPKGF_RUN_ALL_TRIGGERS) == 0) &&
((dbd->flags & APK_DBDIRF_MODIFIED) == 0))
continue;
for (i = 0; i < ipkg->triggers->num; i++) {
if (ipkg->triggers->item[i][0] != '/')
continue;
if (fnmatch(ipkg->triggers->item[i], dbd->rooted_name,
FNM_PATHNAME) != 0)
continue;
*apk_string_array_add(&ipkg->pending_triggers) =
dbd->rooted_name;
break;
}
}
return 0;
}
int apk_db_run_triggers(struct apk_database *db)
{
struct apk_installed_package *ipkg;
apk_hash_foreach(&db->installed.dirs, fire_triggers, db);
list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) {
if (ipkg->pending_triggers == NULL)
continue;
fprintf(stderr, "run triggers: %s\n", ipkg->pkg->name->name);
*apk_string_array_add(&ipkg->pending_triggers) = NULL;
apk_ipkg_run_script(ipkg, db->root_fd, APK_SCRIPT_TRIGGER,
ipkg->pending_triggers->item);
free(ipkg->pending_triggers);
ipkg->pending_triggers = NULL;
}
return 0;
}
int apk_db_cache_active(struct apk_database *db)
{
return db->cache_dir != apk_static_cache_dir;
}
int apk_db_permanent(struct apk_database *db)
{
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;
static int apk_repo_is_remote(struct apk_repository *repo)
{
return repo->csum.type != APK_CHECKSUM_NONE;
}
static struct apk_bstream *apk_repo_file_open(struct apk_repository *repo,
const char *file)
if ((apk_flags & APK_NO_NETWORK) && apk_repo_is_remote(repo))
return NULL;
/* We should not get called for non-repository files */
if (strcmp(repo->url, "cache") == 0)
return NULL;
snprintf(tmp, sizeof(tmp), "%s%s%s",
url, url[strlen(url)-1] == '/' ? "" : "/", file);
return apk_bstream_from_url(tmp);
}
struct apk_repository *apk_db_select_repo(struct apk_database *db,
struct apk_package *pkg)
{
static struct apk_repository cache_repo = {
.url = "cache",
.csum.data = {
0xb0,0x35,0x92,0x80,0x6e,0xfa,0xbf,0xee,0xb7,0x09,
0xf5,0xa7,0x0a,0x7c,0x17,0x26,0x69,0xb0,0x05,0x38 },
.csum.type = APK_CHECKSUM_SHA1,
};
unsigned int repos = pkg->repos;
int i;
/* Always prefer local repositories */
if ((repos & db->local_repos) != 0)
repos &= db->local_repos;
/* Pick first repository providing this package */
for (i = 0; i < APK_MAX_REPOS; i++)
if (repos & BIT(i))
break;
/* If this is a remote repository, and we have no network,
* check that we have it in cache */
if ((i >= APK_MAX_REPOS) ||
((db->local_repos & BIT(i)) == 0 && (apk_flags & APK_NO_NETWORK))) {
char cacheitem[PATH_MAX];
apk_pkg_format_cache(pkg, APK_BLOB_BUF(cacheitem));
if (faccessat(db->cache_fd, cacheitem, R_OK, 0) != 0)
return NULL;
}
if (i >= APK_MAX_REPOS)
return &cache_repo;
return &db->repos[i];
}
int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
{
char cacheitem[PATH_MAX];
if (!apk_repo_is_remote(repo))
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)
apk_error("%s: %s", repo->url, apk_error_str(r));
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);
}
struct apkindex_ctx {
struct apk_database *db;
struct apk_sign_ctx sctx;
int repo, found;
};
static int load_apkindex(void *sctx, const struct apk_file_info *fi,
struct apk_istream *is)
{
struct apkindex_ctx *ctx = (struct apkindex_ctx *) sctx;
struct apk_bstream *bs;
if (apk_sign_ctx_process_file(&ctx->sctx, fi, is) == 0)
return 0;
if (strcmp(fi->name, "APKINDEX") != 0)
return 0;
ctx->found = 1;
bs = apk_bstream_from_istream(is);
apk_db_index_read(ctx->db, bs, ctx->repo);
bs->close(bs, NULL);
return 0;
static int load_index(struct apk_database *db, struct apk_bstream *bs,
int targz, int repo)
{
if (targz) {
struct apk_istream *is;
struct apkindex_ctx ctx;
ctx.db = db;
ctx.repo = repo;
ctx.found = 0;
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);
apk_sign_ctx_free(&ctx.sctx);
if (ctx.found == 0)
} else {
bs = apk_bstream_from_istream(apk_bstream_gunzip(bs));
apk_db_index_read(db, bs, repo);
bs->close(bs, NULL);
}
}
int apk_db_index_read_file(struct apk_database *db, const char *file, int repo)
{
int targz = 1;
if (strstr(file, ".tar.gz") == NULL && strstr(file, ".gz") != NULL)
targz = 0;
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)
{
struct apk_database *db = _db.db;
struct apk_bstream *bs = NULL;
struct apk_repository *repo;
if (repository.ptr == NULL || repository.len == 0 ||
*repository.ptr == '#')
if (db->num_repos >= APK_MAX_REPOS)
return -1;
r = db->num_repos++;
repo = &db->repos[r];
*repo = (struct apk_repository) {
};
char cacheitem[PATH_MAX];
apk_blob_checksum(repository, apk_checksum_default(), &repo->csum);
apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 0);
bs = apk_bstream_from_file(db->cache_fd, cacheitem);
apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 1);
bs = apk_bstream_from_file(db->cache_fd, cacheitem);
db->local_repos |= BIT(r);
bs = apk_repo_file_open(repo, apkindex_tar_gz);
bs = apk_repo_file_open(repo, apk_index_gz);
apk_warning("Failed to open index for %s", repo->url);
}
r = load_index(db, bs, targz, r);
if (r != 0)
apk_error("%s: Bad repository signature", repo->url);
return r;
}
static void extract_cb(void *_ctx, size_t progress)
{
struct install_ctx *ctx = (struct install_ctx *) _ctx;
if (ctx->cb) {
size_t size = ctx->installed_size;
size += muldiv(progress, ctx->current_file_size, APK_PROGRESS_SCALE);
if (size > ctx->pkg->installed_size)
size = ctx->pkg->installed_size;
ctx->cb(ctx->cb_ctx, muldiv(APK_PROGRESS_SCALE, size, ctx->pkg->installed_size));
}
}
static int apk_db_run_pending_script(struct install_ctx *ctx)
{
int r;
if (!ctx->script_pending)
return 0;
if (!ctx->sctx.control_verified)
return 0;
ctx->script_pending = FALSE;
r = apk_ipkg_run_script(ctx->ipkg, ctx->db->root_fd, ctx->script,
ctx->script_args);
if (r != 0)
apk_error("%s-%s: Failed to execute "
"pre-install/upgrade script",
ctx->pkg->name->name, ctx->pkg->version);
return r;
}
static struct apk_db_dir_instance *find_diri(struct apk_installed_package *ipkg,
apk_blob_t dirname,
struct apk_db_dir_instance *curdiri,
struct hlist_node ***tail)
{
struct hlist_node *n;
struct apk_db_dir_instance *diri;
if (curdiri != NULL &&
apk_blob_compare(APK_BLOB_PTR_LEN(curdiri->dir->name,
curdiri->dir->namelen),
dirname) == 0)
return curdiri;
hlist_for_each_entry(diri, n, &ipkg->owned_dirs, pkg_dirs_list) {
if (apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name,
diri->dir->namelen), dirname) == 0) {
if (tail != NULL)
*tail = hlist_tail_ptr(&diri->owned_files);
return diri;
}
}
return NULL;
}
static int parse_replaces(void *_ctx, apk_blob_t blob)
{
struct install_ctx *ctx = (struct install_ctx *) _ctx;
if (blob.len == 0)
return 0;
*apk_name_array_add(&ctx->replaces) = apk_db_get_name(ctx->db, blob);
return 0;
}
static int read_info_line(void *_ctx, apk_blob_t line)
{
struct install_ctx *ctx = (struct install_ctx *) _ctx;
struct apk_installed_package *ipkg = ctx->ipkg;
struct apk_database *db = ctx->db;
apk_blob_t l, r;
if (line.ptr == NULL || line.len < 1 || line.ptr[0] == '#')
return 0;
if (!apk_blob_split(line, APK_BLOB_STR(" = "), &l, &r))
return 0;
if (apk_blob_compare(APK_BLOB_STR("replaces"), l) == 0) {
apk_blob_for_each_segment(r, " ", parse_replaces, ctx);
} else if (apk_blob_compare(APK_BLOB_STR("triggers"), l) == 0) {
if (ipkg->triggers) {
free(ipkg->triggers);
ipkg->triggers = NULL;
}
apk_blob_for_each_segment(r, " ", parse_triggers, ctx->ipkg);
if (ctx->ipkg->triggers && !list_hashed(&ipkg->trigger_pkgs_list))
list_add_tail(&ipkg->trigger_pkgs_list,
&db->installed.triggers);
} else {
apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line);
}
return 0;
}
static int apk_db_install_archive_entry(void *_ctx,
const struct apk_file_info *ae,
{
struct install_ctx *ctx = (struct install_ctx *) _ctx;
struct apk_database *db = ctx->db;
struct apk_package *pkg = ctx->pkg, *opkg;
struct apk_installed_package *ipkg = pkg->ipkg;
apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile;
struct apk_db_dir_instance *diri = ctx->diri;
struct apk_db_file *file;
const char *p;
if (apk_sign_ctx_process_file(&ctx->sctx, ae, is) == 0)
return 0;
/* Package metainfo and script processing */
if (ae->name[0] == '.') {
/* APK 2.0 format */
if (strcmp(ae->name, ".PKGINFO") == 0) {
apk_blob_t blob = apk_blob_from_istream(is, ae->size);
apk_blob_for_each_segment(blob, "\n", read_info_line, ctx);
free(blob.ptr);
return 0;
}
type = apk_script_type(&ae->name[1]);
if (type == APK_SCRIPT_INVALID)
return 0;
} else if (strncmp(ae->name, "var/db/apk/", 11) == 0) {
/* APK 1.0 format */
p = &ae->name[11];
if (strncmp(p, pkg->name->name, strlen(pkg->name->name)) != 0)
return 0;
p += strlen(pkg->name->name) + 1;
if (strncmp(p, pkg->version, strlen(pkg->version)) != 0)
return 0;
p += strlen(pkg->version) + 1;
type = apk_script_type(p);
return 0;
/* Handle script */
if (type != APK_SCRIPT_INVALID) {
apk_ipkg_add_script(ipkg, is, type, ae->size);
if (type == ctx->script)
ctx->script_pending = TRUE;
return apk_db_run_pending_script(ctx);
}
r = apk_db_run_pending_script(ctx);
if (r != 0)
return r;
/* Show progress */
if (ctx->cb) {
size_t size = ctx->installed_size;
if (size > pkg->installed_size)
size = pkg->installed_size;
ctx->cb(ctx->cb_ctx, muldiv(APK_PROGRESS_SCALE, size, pkg->installed_size));
}
ctx->current_file_size = apk_calc_installed_size(ae->size);
if (!S_ISDIR(ae->mode)) {
if (!apk_blob_rsplit(name, '/', &bdir, &bfile))
return 0;
if (bfile.len > 6 && memcmp(bfile.ptr, ".keep_", 6) == 0)
return 0;
/* Make sure the file is part of the cached directory tree */
diri = find_diri(ipkg, bdir, diri, &ctx->file_diri_node);
if (diri == NULL) {
apk_error("%s: File '%*s' entry without directory entry.\n",
pkg->name->name, name.len, name.ptr);
return -1;
file = apk_db_file_query(db, bdir, bfile);
if (file != NULL) {
do {
if (opkg->name == pkg->name)
break;
for (i = 0; ctx->replaces && i < ctx->replaces->num; i++)
if (opkg->name == ctx->replaces->item[i])
break;
if (ctx->replaces && i < ctx->replaces->num)
break;
if (!(apk_flags & APK_FORCE)) {
pkg->name->name, ae->name,
opkg->name->name);
return -1;
}
apk_warning("%s: Overwriting %s owned by %s.",
pkg->name->name, ae->name,
opkg->name->name);
if (opkg != pkg) {
/* Create the file entry without adding it to hash */
file = apk_db_file_new(diri, bfile, &ctx->file_diri_node);
}
if (apk_verbosity >= 3)
apk_message("%s", ae->name);
r = apk_archive_entry_extract(db->root_fd, ae, ".apk-new", is,
/* Hardlinks need special care for checksum */
if (ae->csum.type == APK_CHECKSUM_NONE &&
ae->link_target != NULL) {
do {
struct apk_db_file *lfile;
struct apk_db_dir_instance *ldiri;
struct hlist_node *n;
if (!apk_blob_rsplit(APK_BLOB_STR(ae->link_target),
'/', &bdir, &bfile))
break;
ldiri = find_diri(ipkg, bdir, diri, NULL);
if (ldiri == NULL)
break;
hlist_for_each_entry(lfile, n, &ldiri->owned_files,
diri_files_list) {
if (apk_blob_compare(APK_BLOB_PTR_LEN(lfile->name, lfile->namelen),
bfile) == 0) {
memcpy(&file->csum, &lfile->csum,
sizeof(file->csum));
break;
}
}
} while (0);
} else
memcpy(&file->csum, &ae->csum, sizeof(file->csum));
} else {
if (apk_verbosity >= 3)
apk_message("%s", ae->name);
if (name.ptr[name.len-1] == '/')
name.len--;
ctx->diri_node = hlist_tail_ptr(&ipkg->owned_dirs);
ctx->diri = diri = apk_db_diri_new(db, pkg, name,
&ctx->diri_node);
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(db, diri);
}
ctx->installed_size += ctx->current_file_size;
return r;
}
static void apk_db_purge_pkg(struct apk_database *db,
struct apk_installed_package *ipkg,
{
struct apk_db_file *file;
struct apk_db_file_hash_key key;
struct hlist_node *dc, *dn, *fc, *fn;
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
if (exten == NULL)
diri->dir->flags |= APK_DBDIRF_MODIFIED;
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
snprintf(name, sizeof(name), "%s/%s%s",
diri->dir->name, file->name, exten ?: "");
key = (struct apk_db_file_hash_key) {
.dirname = APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen),
.filename = APK_BLOB_PTR_LEN(file->name, file->namelen),
hash = apk_blob_hash_seed(key.filename, diri->dir->hash);
if (!(diri->dir->flags & APK_DBDIRF_PROTECTED) ||
(apk_flags & APK_PURGE) ||
apk_file_get_info(db->root_fd, name, file->csum.type, &fi) == 0 &&
apk_checksum_compare(&file->csum, &fi.csum) == 0))
unlinkat(db->root_fd, name, 0);
if (apk_verbosity >= 3)
apk_message("%s", name);
__hlist_del(fc, &diri->owned_files.first);
if (exten == NULL) {
apk_hash_delete_hashed(&db->installed.files, APK_BLOB_BUF(&key), hash);
db->installed.stats.files--;
}
apk_db_diri_rmdir(db, diri);
__hlist_del(dc, &ipkg->owned_dirs.first);
}
}
static void apk_db_migrate_files(struct apk_database *db,
struct apk_installed_package *ipkg)
{
struct apk_db_dir_instance *diri;
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;
unsigned long hash;
char name[PATH_MAX], tmpname[PATH_MAX];
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
dir->flags |= APK_DBDIRF_MODIFIED;
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
snprintf(name, sizeof(name), "%s/%s",
diri->dir->name, file->name);
snprintf(tmpname, sizeof(tmpname), "%s/%s.apk-new",
diri->dir->name, file->name);
key = (struct apk_db_file_hash_key) {
.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
.filename = APK_BLOB_PTR_LEN(file->name, file->namelen),
};
hash = apk_blob_hash_seed(key.filename, dir->hash);
/* check for existing file */
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->flags & APK_DBDIRF_PROTECTED))
cstype = ofile->csum.type;
r = apk_file_get_info(db->root_fd, name, cstype, &fi);
if ((diri->dir->flags & APK_DBDIRF_PROTECTED) &&
apk_checksum_compare(&ofile->csum, &fi.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_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))
unlinkat(db->root_fd, tmpname, 0);
renameat(db->root_fd, tmpname,
db->root_fd, name);
}
/* Claim ownership of the file in db */
if (ofile != file) {
if (ofile != NULL) {
hlist_del(&ofile->diri_files_list,
&ofile->diri->owned_files);
apk_hash_delete_hashed(&db->installed.files,
APK_BLOB_BUF(&key), hash);
} else
db->installed.stats.files++;
apk_hash_insert_hashed(&db->installed.files, file, hash);
}
static int apk_db_unpack_pkg(struct apk_database *db,
struct apk_installed_package *ipkg,
apk_progress_cb cb, void *cb_ctx,
char **script_args)
{
struct install_ctx ctx;
struct apk_package *pkg = ipkg->pkg;
int r, need_copy = FALSE;
if (pkg->filename == NULL) {
repo = apk_db_select_repo(db, pkg);
if (repo == NULL) {
apk_error("%s-%s: package is not currently available",
pkg->name->name, pkg->version);
return -1;
}
if (apk_db_cache_active(db) && apk_repo_is_remote(repo)) {
apk_pkg_format_cache(pkg, APK_BLOB_BUF(file));
bs = apk_bstream_from_file(db->cache_fd, file);
}
apk_pkg_format_plain(pkg, APK_BLOB_BUF(file));
bs = apk_repo_file_open(repo, file);
if (apk_repo_is_remote(repo))
bs = apk_bstream_from_file(AT_FDCWD, pkg->filename);
if (!apk_db_cache_active(db))
need_copy = FALSE;
apk_pkg_format_cache(pkg, APK_BLOB_BUF(file));
bs = apk_bstream_tee(bs, db->cachetmp_fd, file);
apk_error("%s: %s", file, strerror(errno));
return errno;
ctx = (struct install_ctx) {
.db = db,
.pkg = pkg,
.ipkg = ipkg,
APK_SCRIPT_PRE_UPGRADE : APK_SCRIPT_PRE_INSTALL,
.script_args = script_args,
.cb = cb,
.cb_ctx = cb_ctx,
};
apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->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);
if (ctx.replaces)
free(ctx.replaces);
if (need_copy) {
if (r == 0)
renameat(db->cachetmp_fd, file, db->cache_fd, file);
else
unlinkat(db->cachetmp_fd, file, 0);
}
pkg->name->name, pkg->version,
r = apk_db_run_pending_script(&ctx);
if (r != 0)
apk_db_migrate_files(db, ipkg);
apk_db_purge_pkg(db, ipkg, ".apk-new");
}
int apk_db_install_pkg(struct apk_database *db,