summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libalpm/be_package.c1
-rw-r--r--lib/libalpm/sync.c82
2 files changed, 59 insertions, 24 deletions
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
index a0534b00..c20c703f 100644
--- a/lib/libalpm/be_package.c
+++ b/lib/libalpm/be_package.c
@@ -287,6 +287,7 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle,
alpm_siglist_t **sigdata)
{
int has_sig;
+ handle->pm_errno = 0;
if(pkgfile == NULL || strlen(pkgfile) == 0) {
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index dda4b241..abd7cdb8 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -909,42 +909,47 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas)
return errors;
}
-static int check_validity(alpm_handle_t *handle, alpm_list_t **data,
+static int check_validity(alpm_handle_t *handle,
size_t total, size_t total_bytes)
{
+ struct validity {
+ alpm_pkg_t *pkg;
+ char *path;
+ alpm_siglist_t *siglist;
+ alpm_siglevel_t level;
+ enum _alpm_errno_t error;
+ };
size_t current = 0, current_bytes = 0;
- int errors = 0;
- alpm_list_t *i;
+ alpm_list_t *i, *errors = NULL;
/* Check integrity of packages */
EVENT(handle, ALPM_EVENT_INTEGRITY_START, NULL, NULL);
for(i = handle->trans->add; i; i = i->next, current++) {
- alpm_pkg_t *spkg = i->data;
- char *filepath;
- alpm_siglevel_t level;
- alpm_siglist_t *siglist = NULL;
+ struct validity v = { i->data, NULL, NULL, 0, 0 };
int percent = (int)(((double)current_bytes / total_bytes) * 100);
PROGRESS(handle, ALPM_PROGRESS_INTEGRITY_START, "", percent,
total, current);
- if(spkg->origin == PKG_FROM_FILE) {
+ if(v.pkg->origin == PKG_FROM_FILE) {
continue; /* pkg_load() has been already called, this package is valid */
}
- current_bytes += spkg->size;
- filepath = _alpm_filecache_find(handle, spkg->filename);
- alpm_db_t *sdb = alpm_pkg_get_db(spkg);
- level = alpm_db_get_siglevel(sdb);
+ current_bytes += v.pkg->size;
+ v.path = _alpm_filecache_find(handle, v.pkg->filename);
+ v.level = alpm_db_get_siglevel(alpm_pkg_get_db(v.pkg));
- if(_alpm_pkg_validate_internal(handle, filepath, spkg, level, &siglist) == -1) {
- prompt_to_delete(handle, filepath, handle->pm_errno);
- errors++;
- *data = alpm_list_add(*data, strdup(spkg->filename));
+ if(_alpm_pkg_validate_internal(handle, v.path, v.pkg,
+ v.level, &v.siglist) == -1) {
+ v.error = handle->pm_errno;
+ struct validity *invalid = malloc(sizeof(struct validity));
+ memcpy(invalid, &v, sizeof(struct validity));
+ errors = alpm_list_add(errors, invalid);
+ } else {
+ alpm_siglist_cleanup(v.siglist);
+ free(v.siglist);
+ free(v.path);
}
- alpm_siglist_cleanup(siglist);
- free(siglist);
- free(filepath);
}
PROGRESS(handle, ALPM_PROGRESS_INTEGRITY_START, "", 100,
@@ -952,10 +957,33 @@ static int check_validity(alpm_handle_t *handle, alpm_list_t **data,
EVENT(handle, ALPM_EVENT_INTEGRITY_DONE, NULL, NULL);
if(errors) {
- if(!handle->pm_errno) {
- RET_ERR(handle, ALPM_ERR_PKG_INVALID, -1);
+ int tryagain = 0;
+ for(i = errors; i; i = i->next) {
+ struct validity *v = i->data;
+ if(v->error == ALPM_ERR_PKG_INVALID_SIG) {
+ int retry = _alpm_process_siglist(handle, v->pkg->name, v->siglist,
+ v->level & ALPM_SIG_PACKAGE_OPTIONAL,
+ v->level & ALPM_SIG_PACKAGE_MARGINAL_OK,
+ v->level & ALPM_SIG_PACKAGE_UNKNOWN_OK);
+ tryagain += retry;
+ } else if(v->error == ALPM_ERR_PKG_INVALID_CHECKSUM) {
+ prompt_to_delete(handle, v->path, v->error);
+ }
+ alpm_siglist_cleanup(v->siglist);
+ free(v->siglist);
+ free(v->path);
+ free(v);
}
- return -1;
+ alpm_list_free(errors);
+
+ if(tryagain == 0) {
+ if(!handle->pm_errno) {
+ RET_ERR(handle, ALPM_ERR_PKG_INVALID, -1);
+ }
+ return -1;
+ }
+ /* we were told at least once we can try again */
+ return 1;
}
return 0;
@@ -1051,8 +1079,14 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data)
/* this can only happen maliciously */
total_bytes = total_bytes ? total_bytes : 1;
- if(check_validity(handle, data, total, total_bytes)) {
- return -1;
+ /* this one is special: -1 is failure, 1 is retry, 0 is success */
+ while(1) {
+ int ret = check_validity(handle, total, total_bytes);
+ if(ret == 0) {
+ break;
+ } else if(ret < 0) {
+ return -1;
+ }
}
if(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY) {