Newer
Older
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_repository_update_all(struct apk_database *db)
{
int i, ret;
for (i = 0; i < db->num_repos; i++) {
ret = apk_repository_update(db, &db->repos[i]);
if (ret < 0)
return ret;
}
return 0;
}
int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
{
struct apk_database *db = _db.db;
struct apk_istream *is = NULL;
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) {
};
bs = apk_db_cache_open(db, repo->url_csum, apk_index_gz);
if (bs == NULL) {
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);
apk_warning("Failed to open index for %s", repo->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;
struct apk_bstream *bs = NULL;
char pkgname[256], file[256];
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,
};
if (apk_parse_tar_gz(bs, apk_db_install_archive_entry, &ctx) != 0)
goto err_close;
bs->close(bs, csum, &length);
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);
}
}
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
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;
}