Skip to content
Snippets Groups Projects
database.c 29.4 KiB
Newer Older
			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));
	}

	/* Installable entry */
	ctx->current_file_size = apk_calc_installed_size(ae->size);
		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);
			opkg = file->diri->pkg;
			if (opkg->name != pkg->name) {
				if (!apk_force) {
					apk_error("%s: Trying to overwrite %s "
						  "owned by %s.\n",
						  pkg->name->name, ae->name,
						  opkg->name->name);
					return -1;
				}
Timo Teräs's avatar
Timo Teräs committed
				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) &&
		    apk_file_get_info(ae->name, &fi) == 0 &&
		    (memcmp(file->csum, fi.csum, sizeof(csum_t)) != 0 ||
		     !csum_valid(file->csum))) {
			/* Protected file. Extract to separate place */
			if (!apk_clean) {
				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));
		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);
		apk_db_diri_mkdir(diri);
	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_dir_instance *diri;
	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),
			};
			unlink(name);
			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--;
		}
		apk_db_diri_rmdir(diri);
		__hlist_del(dc, &pkg->owned_dirs.first);
		apk_db_diri_free(db, diri);
	apk_pkg_set_state(db, pkg, APK_STATE_NO_INSTALL);
}

int apk_db_install_pkg(struct apk_database *db,
		       struct apk_package *oldpkg,
		       struct apk_package *newpkg,
		       apk_progress_cb cb, void *cb_ctx)
	struct apk_bstream *bs;
	struct install_ctx ctx;
	csum_t csum;
	char file[256];
	if (fchdir(db->root_fd) < 0)
	/* 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;


		r = apk_pkg_run_script(oldpkg, db->root_fd,
				       APK_SCRIPT_POST_DEINSTALL);
		return r;
	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_url(file);
		bs = apk_bstream_from_file(newpkg->filename);
	if (bs == NULL) {
		apk_error("%s: %s", file, strerror(errno));

	ctx = (struct install_ctx) {
		.db = db,
		.pkg = newpkg,
		.script = (oldpkg == NULL) ?
			APK_SCRIPT_PRE_INSTALL : APK_SCRIPT_PRE_UPGRADE,
		.cb = cb,
		.cb_ctx = cb_ctx,
	if (apk_parse_tar_gz(bs, apk_db_install_archive_entry, &ctx) != 0)
Timo Teräs's avatar
Timo Teräs committed
	bs->close(bs, csum, NULL);
	apk_pkg_set_state(db, newpkg, APK_STATE_INSTALL);

	if (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);
Timo Teräs's avatar
Timo Teräs committed
	bs->close(bs, NULL, NULL);