libalpm/dload: major refactor of signature downloading
There's a lot of related moving parts here: * Iteration through mirrors is moved back to the calling functions. This allows removal of _alpm_download_single_file and _alpm_download_files. * The download function gets a few more arguments to influence behavior. This allows several different scenarios to customize behavior: - database - database signature (req'd and optional) - package - package via direct URL - package signature via direct URL (req'd and optional) * For databases, we need signatures from the same mirror, so structure the code accordingly. Some-inspiration-from: Dave Reisner <d@falconindy.com> Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
parent
204bbc4714
commit
9579879b1b
4 changed files with 95 additions and 127 deletions
|
@ -78,11 +78,12 @@
|
||||||
*/
|
*/
|
||||||
int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
|
int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
|
||||||
{
|
{
|
||||||
char *dbfile, *syncpath;
|
char *syncpath;
|
||||||
const char *dbpath;
|
const char *dbpath;
|
||||||
|
alpm_list_t *i;
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
int ret;
|
int ret = -1;
|
||||||
mode_t oldmask;
|
mode_t oldmask;
|
||||||
pgp_verify_t check_sig;
|
pgp_verify_t check_sig;
|
||||||
|
|
||||||
|
@ -91,14 +92,7 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
|
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
|
||||||
ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
||||||
|
ASSERT(db->servers != NULL, RET_ERR(PM_ERR_SERVER_NONE, -1));
|
||||||
if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
|
|
||||||
RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(db->treename) + 4;
|
|
||||||
MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
|
|
||||||
sprintf(dbfile, "%s.db", db->treename);
|
|
||||||
|
|
||||||
dbpath = alpm_option_get_dbpath();
|
dbpath = alpm_option_get_dbpath();
|
||||||
len = strlen(dbpath) + 6;
|
len = strlen(dbpath) + 6;
|
||||||
|
@ -112,20 +106,48 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
|
||||||
_alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
|
_alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
|
||||||
syncpath);
|
syncpath);
|
||||||
if(_alpm_makepath(syncpath) != 0) {
|
if(_alpm_makepath(syncpath) != 0) {
|
||||||
free(dbfile);
|
|
||||||
free(syncpath);
|
free(syncpath);
|
||||||
RET_ERR(PM_ERR_SYSTEM, -1);
|
RET_ERR(PM_ERR_SYSTEM, -1);
|
||||||
}
|
}
|
||||||
} else if(!S_ISDIR(buf.st_mode)) {
|
} else if(!S_ISDIR(buf.st_mode)) {
|
||||||
_alpm_log(PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
|
_alpm_log(PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
|
||||||
if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
|
if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
|
||||||
free(dbfile);
|
|
||||||
free(syncpath);
|
free(syncpath);
|
||||||
RET_ERR(PM_ERR_SYSTEM, -1);
|
RET_ERR(PM_ERR_SYSTEM, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
|
check_sig = _alpm_db_get_sigverify_level(db);
|
||||||
|
|
||||||
|
for(i = db->servers; i; i = i->next) {
|
||||||
|
const char *server = i->data;
|
||||||
|
char *fileurl;
|
||||||
|
size_t len;
|
||||||
|
int sig_ret = 0;
|
||||||
|
|
||||||
|
/* print server + filename into a buffer (leave space for .sig) */
|
||||||
|
len = strlen(server) + strlen(db->treename) + 9;
|
||||||
|
CALLOC(fileurl, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1));
|
||||||
|
snprintf(fileurl, len, "%s/%s.db", server, db->treename);
|
||||||
|
|
||||||
|
ret = _alpm_download(fileurl, syncpath, force, 0, 0);
|
||||||
|
|
||||||
|
if(ret == 0 && (check_sig == PM_PGP_VERIFY_ALWAYS ||
|
||||||
|
check_sig == PM_PGP_VERIFY_OPTIONAL)) {
|
||||||
|
int errors_ok = (check_sig == PM_PGP_VERIFY_OPTIONAL);
|
||||||
|
/* if we downloaded a DB, we want the .sig from the same server */
|
||||||
|
snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename);
|
||||||
|
|
||||||
|
sig_ret = _alpm_download(fileurl, syncpath, 1, 0, errors_ok);
|
||||||
|
/* errors_ok suppresses error messages, but not the return code */
|
||||||
|
sig_ret = errors_ok ? 0 : sig_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
FREE(fileurl);
|
||||||
|
if(ret != -1 && sig_ret != -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(ret == 1) {
|
if(ret == 1) {
|
||||||
/* files match, do nothing */
|
/* files match, do nothing */
|
||||||
|
@ -137,51 +159,11 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_sig = _alpm_db_get_sigverify_level(db);
|
|
||||||
|
|
||||||
/* Download and check the signature of the database if needed */
|
|
||||||
if(check_sig != PM_PGP_VERIFY_NEVER) {
|
|
||||||
char *sigfile, *sigfilepath;
|
|
||||||
int sigret;
|
|
||||||
|
|
||||||
len = strlen(dbfile) + 5;
|
|
||||||
MALLOC(sigfile, len, RET_ERR(PM_ERR_MEMORY, -1));
|
|
||||||
sprintf(sigfile, "%s.sig", dbfile);
|
|
||||||
|
|
||||||
/* prevent old signature being used if the following download fails */
|
|
||||||
len = strlen(syncpath) + strlen(sigfile) + 1;
|
|
||||||
MALLOC(sigfilepath, len, RET_ERR(PM_ERR_MEMORY, -1));
|
|
||||||
sprintf(sigfilepath, "%s%s", syncpath, sigfile);
|
|
||||||
_alpm_rmrf(sigfilepath);
|
|
||||||
free(sigfilepath);
|
|
||||||
|
|
||||||
sigret = _alpm_download_single_file(sigfile, db->servers, syncpath, 0);
|
|
||||||
free(sigfile);
|
|
||||||
|
|
||||||
if(sigret == -1 && check_sig == PM_PGP_VERIFY_ALWAYS) {
|
|
||||||
_alpm_log(PM_LOG_ERROR, _("Failed to download signature for db: %s\n"),
|
|
||||||
alpm_strerrorlast());
|
|
||||||
pm_errno = PM_ERR_SIG_INVALID;
|
|
||||||
ret = -1;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
sigret = alpm_db_check_pgp_signature(db);
|
|
||||||
if((check_sig == PM_PGP_VERIFY_ALWAYS && sigret != 0) ||
|
|
||||||
(check_sig == PM_PGP_VERIFY_OPTIONAL && sigret == 1)) {
|
|
||||||
/* pm_errno was set by the checking code */
|
|
||||||
/* TODO: should we just leave the unverified database */
|
|
||||||
ret = -1;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cache needs to be rebuilt */
|
/* Cache needs to be rebuilt */
|
||||||
_alpm_db_free_pkgcache(db);
|
_alpm_db_free_pkgcache(db);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
||||||
free(dbfile);
|
|
||||||
free(syncpath);
|
free(syncpath);
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -156,7 +156,7 @@ static int utimes_long(const char *path, long time)
|
||||||
|
|
||||||
|
|
||||||
static int curl_download_internal(const char *url, const char *localpath,
|
static int curl_download_internal(const char *url, const char *localpath,
|
||||||
int force, int allow_resume)
|
int force, int allow_resume, int errors_ok)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
FILE *localf = NULL;
|
FILE *localf = NULL;
|
||||||
|
@ -249,9 +249,14 @@ static int curl_download_internal(const char *url, const char *localpath,
|
||||||
if(handle->curlerr == CURLE_ABORTED_BY_CALLBACK) {
|
if(handle->curlerr == CURLE_ABORTED_BY_CALLBACK) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if(handle->curlerr != CURLE_OK) {
|
} else if(handle->curlerr != CURLE_OK) {
|
||||||
pm_errno = PM_ERR_LIBCURL;
|
if(!errors_ok) {
|
||||||
_alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"),
|
pm_errno = PM_ERR_LIBCURL;
|
||||||
dlfile.filename, hostname, error_buffer);
|
_alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"),
|
||||||
|
dlfile.filename, hostname, error_buffer);
|
||||||
|
} else {
|
||||||
|
_alpm_log(PM_LOG_DEBUG, "failed retrieving file '%s' from %s : %s\n",
|
||||||
|
dlfile.filename, hostname, error_buffer);
|
||||||
|
}
|
||||||
unlink(tempfile);
|
unlink(tempfile);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -289,8 +294,6 @@ cleanup:
|
||||||
utimes_long(tempfile, remote_time);
|
utimes_long(tempfile, remote_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: A signature download will need to return success here as well before
|
|
||||||
* we're willing to rotate the new file into place. */
|
|
||||||
if(ret == 0) {
|
if(ret == 0) {
|
||||||
rename(tempfile, destfile);
|
rename(tempfile, destfile);
|
||||||
}
|
}
|
||||||
|
@ -310,78 +313,24 @@ cleanup:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int download(const char *url, const char *localpath,
|
int _alpm_download(const char *url, const char *localpath,
|
||||||
int force)
|
int force, int allow_resume, int errors_ok)
|
||||||
{
|
{
|
||||||
if(handle->fetchcb == NULL) {
|
if(handle->fetchcb == NULL) {
|
||||||
#ifdef HAVE_LIBCURL
|
#ifdef HAVE_LIBCURL
|
||||||
return curl_download_internal(url, localpath, force, 1);
|
return curl_download_internal(url, localpath, force, allow_resume, errors_ok);
|
||||||
#else
|
#else
|
||||||
RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
|
RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
int ret = handle->fetchcb(url, localpath, force);
|
int ret = handle->fetchcb(url, localpath, force);
|
||||||
if(ret == -1) {
|
if(ret == -1 && !errors_ok) {
|
||||||
RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
|
RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Download a single file
|
|
||||||
* - servers must be a list of urls WITHOUT trailing slashes.
|
|
||||||
*
|
|
||||||
* RETURN: 0 for successful download
|
|
||||||
* 1 if the files are identical
|
|
||||||
* -1 on error
|
|
||||||
*/
|
|
||||||
int _alpm_download_single_file(const char *filename,
|
|
||||||
alpm_list_t *servers, const char *localpath,
|
|
||||||
int force)
|
|
||||||
{
|
|
||||||
alpm_list_t *i;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
ASSERT(servers != NULL, RET_ERR(PM_ERR_SERVER_NONE, -1));
|
|
||||||
|
|
||||||
for(i = servers; i; i = i->next) {
|
|
||||||
const char *server = i->data;
|
|
||||||
char *fileurl = NULL;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* print server + filename into a buffer */
|
|
||||||
len = strlen(server) + strlen(filename) + 2;
|
|
||||||
CALLOC(fileurl, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1));
|
|
||||||
snprintf(fileurl, len, "%s/%s", server, filename);
|
|
||||||
|
|
||||||
ret = download(fileurl, localpath, force);
|
|
||||||
FREE(fileurl);
|
|
||||||
if(ret != -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _alpm_download_files(alpm_list_t *files,
|
|
||||||
alpm_list_t *servers, const char *localpath)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
alpm_list_t *lp;
|
|
||||||
|
|
||||||
for(lp = files; lp; lp = lp->next) {
|
|
||||||
char *filename = lp->data;
|
|
||||||
if(_alpm_download_single_file(filename, servers,
|
|
||||||
localpath, 0) == -1) {
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Fetch a remote pkg. */
|
/** Fetch a remote pkg. */
|
||||||
char SYMEXPORT *alpm_fetch_pkgurl(const char *url)
|
char SYMEXPORT *alpm_fetch_pkgurl(const char *url)
|
||||||
{
|
{
|
||||||
|
@ -397,13 +346,35 @@ char SYMEXPORT *alpm_fetch_pkgurl(const char *url)
|
||||||
cachedir = _alpm_filecache_setup();
|
cachedir = _alpm_filecache_setup();
|
||||||
|
|
||||||
/* download the file */
|
/* download the file */
|
||||||
ret = download(url, cachedir, 0);
|
ret = _alpm_download(url, cachedir, 0, 1, 0);
|
||||||
if(ret == -1) {
|
if(ret == -1) {
|
||||||
_alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url);
|
_alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
_alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", url);
|
_alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", url);
|
||||||
|
|
||||||
|
/* attempt to download the signature */
|
||||||
|
if(ret == 0 && (handle->sigverify == PM_PGP_VERIFY_ALWAYS ||
|
||||||
|
handle->sigverify == PM_PGP_VERIFY_OPTIONAL)) {
|
||||||
|
char *sig_url;
|
||||||
|
size_t len;
|
||||||
|
int errors_ok = (handle->sigverify == PM_PGP_VERIFY_OPTIONAL);
|
||||||
|
|
||||||
|
len = strlen(url) + 5;
|
||||||
|
CALLOC(sig_url, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL));
|
||||||
|
snprintf(sig_url, len, "%s.sig", url);
|
||||||
|
|
||||||
|
ret = _alpm_download(sig_url, cachedir, 1, 0, errors_ok);
|
||||||
|
if(ret == -1 && !errors_ok) {
|
||||||
|
_alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), sig_url);
|
||||||
|
/* Warn now, but don't return NULL. We will fail later during package
|
||||||
|
* load time. */
|
||||||
|
} else if(ret == 0) {
|
||||||
|
_alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", sig_url);
|
||||||
|
}
|
||||||
|
FREE(sig_url);
|
||||||
|
}
|
||||||
|
|
||||||
/* we should be able to find the file the second time around */
|
/* we should be able to find the file the second time around */
|
||||||
filepath = _alpm_filecache_find(filename);
|
filepath = _alpm_filecache_find(filename);
|
||||||
return filepath;
|
return filepath;
|
||||||
|
|
|
@ -31,12 +31,8 @@ struct fileinfo {
|
||||||
double initial_size;
|
double initial_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
int _alpm_download_single_file(const char *filename,
|
int _alpm_download(const char *url, const char *localpath,
|
||||||
alpm_list_t *servers, const char *localpath,
|
int force, int allow_resume, int errors_ok);
|
||||||
int force);
|
|
||||||
|
|
||||||
int _alpm_download_files(alpm_list_t *files,
|
|
||||||
alpm_list_t *servers, const char *localpath);
|
|
||||||
|
|
||||||
#endif /* _ALPM_DLOAD_H */
|
#endif /* _ALPM_DLOAD_H */
|
||||||
|
|
||||||
|
|
|
@ -689,8 +689,8 @@ static int test_md5sum(pmtrans_t *trans, const char *filepath,
|
||||||
|
|
||||||
int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
|
int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
|
||||||
{
|
{
|
||||||
alpm_list_t *i, *j, *files = NULL;
|
alpm_list_t *i, *j, *k;
|
||||||
alpm_list_t *deltas = NULL;
|
alpm_list_t *files = NULL, *deltas = NULL;
|
||||||
size_t numtargs, current = 0, replaces = 0;
|
size_t numtargs, current = 0, replaces = 0;
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
const char *cachedir = NULL;
|
const char *cachedir = NULL;
|
||||||
|
@ -758,7 +758,26 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
|
||||||
|
|
||||||
if(files) {
|
if(files) {
|
||||||
EVENT(trans, PM_TRANS_EVT_RETRIEVE_START, current->treename, NULL);
|
EVENT(trans, PM_TRANS_EVT_RETRIEVE_START, current->treename, NULL);
|
||||||
errors = _alpm_download_files(files, current->servers, cachedir);
|
for(j = files; j; j = j->next) {
|
||||||
|
const char *filename = j->data;
|
||||||
|
for(k = current->servers; k; k = k->next) {
|
||||||
|
const char *server = k->data;
|
||||||
|
char *fileurl;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* print server + filename into a buffer */
|
||||||
|
len = strlen(server) + strlen(filename) + 2;
|
||||||
|
CALLOC(fileurl, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1));
|
||||||
|
snprintf(fileurl, len, "%s/%s", server, filename);
|
||||||
|
|
||||||
|
ret = _alpm_download(fileurl, cachedir, 0, 1, 0);
|
||||||
|
FREE(fileurl);
|
||||||
|
if(ret != -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(errors) {
|
if(errors) {
|
||||||
_alpm_log(PM_LOG_WARNING, _("failed to retrieve some files from %s\n"),
|
_alpm_log(PM_LOG_WARNING, _("failed to retrieve some files from %s\n"),
|
||||||
|
|
Loading…
Add table
Reference in a new issue