Newer
Older
int apk_cache_exists(struct apk_database *db, csum_t 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;
}
int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
{
if (!csum_valid(repo->url_csum))
return 0;
return apk_cache_download(db, repo->url_csum, repo->url, apk_index_gz);
}
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.ptr == '\0'
|| *repository.ptr == '#')
return 0;
if (db->num_repos >= APK_MAX_REPOS)
return -1;
r = db->num_repos++;
repo = &db->repos[r];
*repo = (struct apk_repository) {
};
if (apk_flags & APK_UPDATE_CACHE)
n = apk_repository_update(db, repo);
bs = apk_db_cache_open(db, repo->url_csum, apk_index_gz);
if (bs == NULL) {
if (n == 1)
n = apk_repository_update(db, repo);
bs = apk_db_cache_open(db, repo->url_csum,
apk_index_gz);
bs = apk_repository_file_open(repo, apk_index_gz);
bs = apk_bstream_from_istream(apk_bstream_gunzip(bs, TRUE));
if (bs == NULL) {
apk_warning("Failed to open index for %s", repo->url);
return -1;
}
apk_db_index_read(db, bs, r);
bs->close(bs, NULL);
return 0;
}
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_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;
apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile;
struct apk_db_dir_instance *diri = ctx->diri;
struct apk_db_file *file;
struct apk_file_info fi;
char alt_name[PATH_MAX];
const char *p;
/* Package metainfo and script processing */
if (ae->name[0] == '.') {
/* APK 2.0 format */
if (strcmp(ae->name, ".INSTALL") == 0)
type = APK_SCRIPT_GENERIC;
else
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_pkg_add_script(pkg, is, type, ae->size);
if (type == APK_SCRIPT_GENERIC ||
type == ctx->script) {
r = apk_pkg_run_script(pkg, db->root_fd, ctx->script);
if (r != 0)
apk_error("%s-%s: Failed to execute pre-install/upgrade script",
pkg->name->name, pkg->version);
}
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 */
if (diri == NULL ||
apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen), bdir) != 0) {
hlist_for_each_entry(diri, n, &pkg->owned_dirs, pkg_dirs_list) {
if (apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen), bdir) == 0)
break;
}
if (diri == NULL) {
apk_error("%s: File '%*s' entry without directory entry.\n",
pkg->name->name, name.len, name.ptr);
return -1;
}
ctx->diri = diri;
ctx->file_diri_node = hlist_tail_ptr(&diri->owned_files);
file = apk_db_file_get(db, diri, bfile, &ctx->file_diri_node);
if (file == NULL) {
apk_error("%s: Failed to create fdb entry for '%*s'\n",
pkg->name->name, name.len, name.ptr);
return -1;
}
if (file->diri != diri) {
if (opkg->name != pkg->name) {
if (!(apk_flags & APK_FORCE)) {
apk_error("%s: Trying to overwrite %s "
"owned by %s.\n",
pkg->name->name, ae->name,
opkg->name->name);
return -1;
}
apk_warning("%s: Overwriting %s owned by %s.\n",
pkg->name->name, ae->name,
opkg->name->name);
apk_db_file_change_owner(db, file, diri,
&ctx->file_diri_node);
}
if (apk_verbosity > 1)
printf("%s\n", ae->name);
if ((diri->dir->flags & APK_DBDIRF_PROTECTED) &&
(memcmp(file->csum, fi.csum, sizeof(csum_t)) != 0 ||
/* Protected file. Extract to separate place */
if (!(apk_flags & APK_CLEAN_PROTECTED)) {
snprintf(alt_name, sizeof(alt_name),
"%s/%s.apk-new",
r = apk_archive_entry_extract(ae, is, alt_name,
extract_cb, ctx);
/* remove identical apk-new */
if (memcmp(ae->csum, fi.csum, sizeof(csum_t)) == 0)
unlink(alt_name);
r = apk_archive_entry_extract(ae, is, NULL,
extract_cb, ctx);
}
memcpy(file->csum, ae->csum, sizeof(csum_t));
} else {
if (apk_verbosity > 1)
printf("%s\n", ae->name);
if (name.ptr[name.len-1] == '/')
name.len--;
if (ctx->diri_node == NULL)
ctx->diri_node = hlist_tail_ptr(&pkg->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);
}
ctx->installed_size += ctx->current_file_size;
return r;
}
static void apk_db_purge_pkg(struct apk_database *db,
struct apk_package *pkg)
{
struct apk_db_file *file;
struct apk_db_file_hash_key key;
struct hlist_node *dc, *dn, *fc, *fn;
char name[1024];
hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) {
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
snprintf(name, sizeof(name), "%s/%s",
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 (apk_verbosity > 1)
printf("%s\n", name);
__hlist_del(fc, &diri->owned_files.first);
apk_hash_delete_hashed(&db->installed.files, APK_BLOB_BUF(&key), hash);
db->installed.stats.files--;
}
__hlist_del(dc, &pkg->owned_dirs.first);
}
apk_pkg_set_state(db, pkg, APK_PKG_NOT_INSTALLED);
}
static int apk_db_gzip_part(void *pctx, EVP_MD_CTX *mdctx, int part)
{
struct install_ctx *ctx = (struct install_ctx *) pctx;
switch (part) {
case APK_MPART_BEGIN:
EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
break;
case APK_MPART_END:
EVP_DigestFinal_ex(mdctx, ctx->data_csum, NULL);
break;
}
return 0;
}
static int apk_db_unpack_pkg(struct apk_database *db,
struct apk_package *newpkg,
int upgrade, apk_progress_cb cb, void *cb_ctx)
{
struct install_ctx ctx;
size_t length;
snprintf(pkgname, sizeof(pkgname), "%s-%s.apk",
newpkg->name->name, newpkg->version);
if (newpkg->filename == NULL) {
for (i = 0; i < APK_MAX_REPOS; i++)
if (newpkg->repos & BIT(i))
break;
if (i >= APK_MAX_REPOS) {
apk_error("%s-%s: not present in any repository",
newpkg->name->name, newpkg->version);
return -1;
}
if (apk_db_cache_active(db) && csum_valid(repo->url_csum))
bs = apk_db_cache_open(db, newpkg->csum, pkgname);
if (bs == NULL) {
snprintf(file, sizeof(file), "%s/%s",
repo->url, pkgname);
bs = apk_bstream_from_url(file);
if (csum_valid(repo->url_csum))
need_copy = TRUE;
}
} else {
bs = apk_bstream_from_file(newpkg->filename);
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_error("%s: %s", file, strerror(errno));
return errno;
ctx = (struct install_ctx) {
.db = db,
.pkg = newpkg,
APK_SCRIPT_PRE_UPGRADE : APK_SCRIPT_PRE_INSTALL,
.cb = cb,
.cb_ctx = cb_ctx,
};
tar = apk_bstream_gunzip_mpart(bs, FALSE, apk_db_gzip_part, &ctx);
if (apk_parse_tar(tar, apk_db_install_archive_entry, &ctx) != 0)
goto err_close;
bs->close(bs, &length);
/* Check the package checksum */
if (memcmp(ctx.data_csum, newpkg->csum, sizeof(csum_t)) != 0)
apk_warning("%s-%s: checksum does not match",
newpkg->name->name, newpkg->version);
if (need_copy) {
if (length == newpkg->size) {
char file2[256];
apk_db_cache_get_name(file2, sizeof(file2), db,
newpkg->csum, pkgname, FALSE);
rename(file, file2);
} else {
unlink(file);
}
}
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
return -1;
}
int apk_db_install_pkg(struct apk_database *db,
struct apk_package *oldpkg,
struct apk_package *newpkg,
apk_progress_cb cb, void *cb_ctx)
{
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,
APK_SCRIPT_PRE_DEINSTALL);
if (r != 0)
return r;
apk_db_purge_pkg(db, oldpkg);
r = apk_pkg_run_script(oldpkg, db->root_fd,
APK_SCRIPT_POST_DEINSTALL);
return r;
}
/* Install the new stuff */
if (!(newpkg->name->flags & APK_NAME_VIRTUAL)) {
r = apk_db_unpack_pkg(db, newpkg, (oldpkg != NULL), cb, cb_ctx);
if (r != 0)
return r;
}
apk_pkg_set_state(db, newpkg, APK_PKG_INSTALLED);
if (oldpkg != NULL)
apk_db_purge_pkg(db, oldpkg);
r = apk_pkg_run_script(newpkg, db->root_fd,
(oldpkg == NULL) ?
APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE);
apk_error("%s-%s: Failed to execute post-install/upgrade script",
newpkg->name->name, newpkg->version);
return r;
}