static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) { const char *cachedir; alpm_list_t *i, *j; alpm_list_t *files = NULL; int errors = 0; cachedir = _alpm_filecache_setup(handle); handle->trans->state = STATE_DOWNLOADING; /* Total progress - figure out the total download size if required to * pass to the callback. This function is called once, and it is up to the * frontend to compute incremental progress. */ if(handle->totaldlcb) { off_t total_size = (off_t)0; /* sum up the download size for each package and store total */ for(i = handle->trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; total_size += spkg->download_size; } handle->totaldlcb(total_size); } /* group sync records by repository and download */ for(i = handle->dbs_sync; i; i = i->next) { alpm_db_t *current = i->data; for(j = handle->trans->add; j; j = j->next) { alpm_pkg_t *spkg = j->data; if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) { alpm_list_t *delta_path = spkg->delta_path; if(delta_path) { /* using deltas */ alpm_list_t *dlts; for(dlts = delta_path; dlts; dlts = dlts->next) { alpm_delta_t *delta = dlts->data; if(delta->download_size != 0) { struct dload_payload *dpayload; CALLOC(dpayload, 1, sizeof(*dpayload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); STRDUP(dpayload->filename, delta->delta, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); dpayload->max_size = delta->download_size; files = alpm_list_add(files, dpayload); } /* keep a list of all the delta files for md5sums */ *deltas = alpm_list_add(*deltas, delta); } } else if(spkg->download_size != 0) { struct dload_payload *payload; ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); STRDUP(payload->filename, spkg->filename, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); payload->max_size = alpm_pkg_get_size(spkg); files = alpm_list_add(files, payload); } } } if(files) { EVENT(handle->trans, ALPM_TRANS_EVT_RETRIEVE_START, current->treename, NULL); for(j = files; j; j = j->next) { struct dload_payload *payload = j->data; alpm_list_t *server; int ret = -1; for(server = current->servers; server; server = server->next) { const char *server_url = server->data; size_t len; /* print server + filename into a buffer */ len = strlen(server_url) + strlen(payload->filename) + 2; CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload->fileurl, len, "%s/%s", server_url, payload->filename); payload->handle = handle; payload->allow_resume = 1; ret = _alpm_download(payload, cachedir, NULL); if(ret != -1) { break; } } if(ret == -1) { errors++; } } alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_free); alpm_list_free(files); files = NULL; if(errors) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files from %s\n"), current->treename); if(handle->pm_errno == 0) { handle->pm_errno = ALPM_ERR_RETRIEVE; } return -1; } } } for(j = handle->trans->add; j; j = j->next) { alpm_pkg_t *pkg = j->data; pkg->infolevel &= ~INFRQ_DSIZE; pkg->download_size = 0; } /* clear out value to let callback know we are done */ if(handle->totaldlcb) { handle->totaldlcb(0); } return 0; }
/** Fetch a remote pkg. */ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) { char *filepath; const char *cachedir; char *final_file = NULL, *final_pkg_url = NULL; struct dload_payload payload; int ret = 0; CHECK_HANDLE(handle, return NULL); ASSERT(url, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL)); /* find a valid cache dir to download to */ cachedir = _alpm_filecache_setup(handle); memset(&payload, 0, sizeof(struct dload_payload)); /* attempt to find the file in our pkgcache */ filepath = filecache_find_url(handle, url); if(filepath == NULL) { STRDUP(payload.fileurl, url, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); payload.allow_resume = 1; payload.handle = handle; payload.trust_remote_name = 1; /* download the file */ ret = _alpm_download(&payload, cachedir, &final_file, &final_pkg_url); _alpm_dload_payload_reset(&payload); if(ret == -1) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); free(final_file); return NULL; } _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", url); } /* attempt to download the signature */ if(ret == 0 && final_pkg_url && (handle->siglevel & ALPM_SIG_PACKAGE)) { char *sig_filepath, *sig_final_file = NULL; size_t len; len = strlen(final_pkg_url) + 5; MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); snprintf(payload.fileurl, len, "%s.sig", final_pkg_url); sig_filepath = filecache_find_url(handle, payload.fileurl); if(sig_filepath == NULL) { payload.handle = handle; payload.trust_remote_name = 1; payload.force = 1; payload.errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); /* set hard upper limit of 16KiB */ payload.max_size = 16 * 1024; ret = _alpm_download(&payload, cachedir, &sig_final_file, NULL); if(ret == -1 && !payload.errors_ok) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), payload.fileurl); /* Warn now, but don't return NULL. We will fail later during package * load time. */ } else if(ret == 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", payload.fileurl); } FREE(sig_final_file); } free(sig_filepath); _alpm_dload_payload_reset(&payload); } /* we should be able to find the file the second time around */ if(filepath == NULL) { filepath = _alpm_filecache_find(handle, final_file); } free(final_file); return filepath; }
/** Applies delta files to create an upgraded package file. * * All intermediate files are deleted, leaving only the starting and * ending package files. * * @param handle the context handle * * @return 0 if all delta files were able to be applied, 1 otherwise. */ static int apply_deltas(alpm_handle_t *handle) { alpm_list_t *i; int ret = 0; const char *cachedir = _alpm_filecache_setup(handle); alpm_trans_t *trans = handle->trans; for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; alpm_list_t *delta_path = spkg->delta_path; alpm_list_t *dlts = NULL; if(!delta_path) { continue; } for(dlts = delta_path; dlts; dlts = dlts->next) { alpm_delta_t *d = dlts->data; char *delta, *from, *to; char command[PATH_MAX]; size_t len = 0; delta = _alpm_filecache_find(handle, d->delta); /* the initial package might be in a different cachedir */ if(dlts == delta_path) { from = _alpm_filecache_find(handle, d->from); } else { /* len = cachedir len + from len + '/' + null */ len = strlen(cachedir) + strlen(d->from) + 2; CALLOC(from, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(from, len, "%s/%s", cachedir, d->from); } len = strlen(cachedir) + strlen(d->to) + 2; CALLOC(to, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(to, len, "%s/%s", cachedir, d->to); /* build the patch command */ if(endswith(to, ".gz")) { /* special handling for gzip : we disable timestamp with -n option */ snprintf(command, PATH_MAX, "xdelta3 -d -q -R -c -s %s %s | gzip -n > %s", from, delta, to); } else { snprintf(command, PATH_MAX, "xdelta3 -d -q -s %s %s %s", from, delta, to); } _alpm_log(handle, ALPM_LOG_DEBUG, "command: %s\n", command); EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCH_START, d->to, d->delta); int retval = system(command); if(retval == 0) { EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCH_DONE, NULL, NULL); /* delete the delta file */ unlink(delta); /* Delete the 'from' package but only if it is an intermediate * package. The starting 'from' package should be kept, just * as if deltas were not used. */ if(dlts != delta_path) { unlink(from); } } FREE(from); FREE(to); FREE(delta); if(retval != 0) { /* one delta failed for this package, cancel the remaining ones */ EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL); handle->pm_errno = ALPM_ERR_DLT_PATCHFAILED; ret = 1; break; } } } return ret; }