Newer
Older
if (!apk_db_cache_has(db, db->repos[r].cache)) {
n = apk_repository_update(db, &db->repos[r]);
if (n < 0)
return n;
}
name = db->repos[r].cache;
is = apk_bstream_gunzip(apk_db_cache_open(db, db->repos[r].cache), 1);
} else {
name = "APK_INDEX.gz";
is = apk_bstream_gunzip(apk_repository_file_open(&db->repos[r], name), 1);
}
apk_warning("Failed to open index for %s", db->repos[r].url);
return -1;
}
apk_db_index_read(db, is, r);
is->close(is);
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 ||
strncmp(diri->dir->dirname, bdir.ptr, bdir.len) != 0 ||
diri->dir->dirname[bdir.len] != 0) {
struct hlist_node *n;
hlist_for_each_entry(diri, n, &pkg->owned_dirs, pkg_dirs_list) {
if (strncmp(diri->dir->dirname, bdir.ptr, bdir.len) == 0 &&
diri->dir->dirname[bdir.len] == 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",
diri->dir->dirname, file->filename);
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",
diri->dir->dirname,
file->filename);
key = (struct apk_db_file_hash_key) {
.dirname = APK_BLOB_STR(diri->dir->dirname),
.filename = APK_BLOB_STR(file->filename),
};
if (apk_verbosity > 1)
printf("%s\n", name);
__hlist_del(fc, &diri->owned_files.first);
apk_hash_delete(&db->installed.files,
APK_BLOB_BUF(&key));
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_unpack_pkg(struct apk_database *db,
struct apk_package *newpkg,
int upgrade, csum_t csum,
apk_progress_cb cb, void *cb_ctx)
{
struct install_ctx ctx;
char file[256];
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;
}
snprintf(file, sizeof(file),
"%s/%s-%s.apk",
db->repos[i].url,
newpkg->name->name, newpkg->version);
bs = apk_bstream_from_file(newpkg->filename);
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,
};
if (apk_parse_tar_gz(bs, apk_db_install_archive_entry, &ctx) != 0)
goto err_close;
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
return 0;
err_close:
bs->close(bs, NULL, NULL);
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)
{
csum_t csum;
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), csum,
cb, cb_ctx);
if (r != 0)
return r;
}
apk_pkg_set_state(db, newpkg, APK_PKG_INSTALLED);
if (!(newpkg->name->flags & APK_NAME_VIRTUAL) &&
memcmp(csum, newpkg->csum, sizeof(csum)) != 0)
apk_warning("%s-%s: checksum does not match",
newpkg->name->name, newpkg->version);
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;
}