示例#1
0
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;
}
示例#2
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;
}
示例#3
0
/** 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;
}