Esempio n. 1
0
File: delta.c Progetto: mineo/pacman
static void graph_init_size(pmhandle_t *handle, alpm_list_t *vertices)
{
	alpm_list_t *i;

	for(i = vertices; i; i = i->next) {
		char *fpath, *md5sum;
		pmgraph_t *v = i->data;
		pmdelta_t *vdelta = v->data;

		/* determine whether the delta file already exists */
		fpath = _alpm_filecache_find(handle, vdelta->delta);
		md5sum = alpm_compute_md5sum(fpath);
		if(fpath && md5sum && strcmp(md5sum, vdelta->delta_md5) == 0) {
			vdelta->download_size = 0;
		}
		FREE(fpath);
		FREE(md5sum);

		/* determine whether a base 'from' file exists */
		fpath = _alpm_filecache_find(handle, vdelta->from);
		if(fpath) {
			v->weight = vdelta->download_size;
		}
		FREE(fpath);
	}
}
Esempio n. 2
0
static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas)
{
	alpm_list_t *i, *errors = NULL;

	if(!deltas) {
		return 0;
	}

	/* Check integrity of deltas */
	EVENT(handle, ALPM_EVENT_DELTA_INTEGRITY_START, NULL, NULL);
	for(i = deltas; i; i = i->next) {
		alpm_delta_t *d = i->data;
		char *filepath = _alpm_filecache_find(handle, d->delta);

		if(_alpm_test_checksum(filepath, d->delta_md5, ALPM_PKG_VALIDATION_MD5SUM)) {
			errors = alpm_list_add(errors, filepath);
		} else {
			FREE(filepath);
		}
	}
	EVENT(handle, ALPM_EVENT_DELTA_INTEGRITY_DONE, NULL, NULL);

	if(errors) {
		for(i = errors; i; i = i->next) {
			char *filepath = i->data;
			prompt_to_delete(handle, filepath, ALPM_ERR_DLT_INVALID);
			FREE(filepath);
		}
		alpm_list_free(errors);
		handle->pm_errno = ALPM_ERR_DLT_INVALID;
		return -1;
	}
	return 0;
}
Esempio n. 3
0
static void graph_init_size(alpm_handle_t *handle, alpm_list_t *vertices)
{
	alpm_list_t *i;

	for(i = vertices; i; i = i->next) {
		char *fpath, *md5sum;
		alpm_graph_t *v = i->data;
		alpm_delta_t *vdelta = v->data;

		/* determine whether the delta file already exists */
		fpath = _alpm_filecache_find(handle, vdelta->delta);
		if(fpath) {
			md5sum = alpm_compute_md5sum(fpath);
			if(md5sum && strcmp(md5sum, vdelta->delta_md5) == 0) {
				vdelta->download_size = 0;
			}
			FREE(md5sum);
			FREE(fpath);
		} else {
			char *fnamepart;
			CALLOC(fnamepart, strlen(vdelta->delta) + 6, sizeof(char), return);
			sprintf(fnamepart, "%s.part", vdelta->delta);
			fpath = _alpm_filecache_find(handle, fnamepart);
			if(fpath) {
				struct stat st;
				if(stat(fpath, &st) == 0) {
					vdelta->download_size = vdelta->delta_size - st.st_size;
					vdelta->download_size = vdelta->download_size < 0 ? 0 : vdelta->download_size;
				}
				FREE(fpath);
			}
			FREE(fnamepart);
		}

		/* determine whether a base 'from' file exists */
		fpath = _alpm_filecache_find(handle, vdelta->from);
		if(fpath) {
			v->weight = vdelta->download_size;
		}
		FREE(fpath);
	}
}
Esempio n. 4
0
/** Compute the size of the files that will be downloaded to install a
 * package.
 * @param newpkg the new package to upgrade to
 */
static int compute_download_size(alpm_pkg_t *newpkg)
{
	const char *fname;
	char *fpath;
	off_t size = 0;
	alpm_handle_t *handle = newpkg->handle;

	if(newpkg->origin != PKG_FROM_SYNCDB) {
		newpkg->infolevel |= INFRQ_DSIZE;
		newpkg->download_size = 0;
		return 0;
	}

	fname = alpm_pkg_get_filename(newpkg);
	ASSERT(fname != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1));
	fpath = _alpm_filecache_find(handle, fname);

	if(fpath) {
		FREE(fpath);
		size = 0;
	} else if(handle->usedelta) {
		off_t dltsize;
		off_t pkgsize = alpm_pkg_get_size(newpkg);

		dltsize = _alpm_shortest_delta_path(handle,
			alpm_pkg_get_deltas(newpkg),
			alpm_pkg_get_filename(newpkg),
			&newpkg->delta_path);

		if(newpkg->delta_path && (dltsize < pkgsize * MAX_DELTA_RATIO)) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "using delta size\n");
			size = dltsize;
		} else {
			_alpm_log(handle, ALPM_LOG_DEBUG, "using package size\n");
			size = alpm_pkg_get_size(newpkg);
			alpm_list_free(newpkg->delta_path);
			newpkg->delta_path = NULL;
		}
	} else {
		size = alpm_pkg_get_size(newpkg);
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "setting download size %jd for pkg %s\n",
			(intmax_t)size, alpm_pkg_get_name(newpkg));

	newpkg->infolevel |= INFRQ_DSIZE;
	newpkg->download_size = size;
	return 0;
}
Esempio n. 5
0
static char *filecache_find_url(alpm_handle_t *handle, const char *url)
{
	const char *filebase = strrchr(url, '/');

	if(filebase == NULL) {
		return NULL;
	}

	filebase++;
	if(filebase == '\0') {
		return NULL;
	}

	return _alpm_filecache_find(handle, filebase);
}
Esempio n. 6
0
static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas,
		alpm_list_t **data)
{
	int errors = 0, ret = 0;
	alpm_list_t *i;
	alpm_trans_t *trans = handle->trans;

	if(!deltas) {
		return 0;
	}

	/* Check integrity of deltas */
	EVENT(trans, ALPM_TRANS_EVT_DELTA_INTEGRITY_START, NULL, NULL);

	for(i = deltas; i; i = i->next) {
		alpm_delta_t *d = alpm_list_getdata(i);
		char *filepath = _alpm_filecache_find(handle, d->delta);

		if(test_md5sum(trans, filepath, d->delta_md5) != 0) {
			errors++;
			*data = alpm_list_add(*data, strdup(d->delta));
		}
		FREE(filepath);
	}
	if(errors) {
		handle->pm_errno = ALPM_ERR_DLT_INVALID;
		return -1;
	}
	EVENT(trans, ALPM_TRANS_EVT_DELTA_INTEGRITY_DONE, NULL, NULL);

	/* Use the deltas to generate the packages */
	EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCHES_START, NULL, NULL);
	ret = apply_deltas(handle);
	EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCHES_DONE, NULL, NULL);
	return ret;
}
Esempio n. 7
0
/** Compute the size of the files that will be downloaded to install a
 * package.
 * @param newpkg the new package to upgrade to
 */
static int compute_download_size(alpm_pkg_t *newpkg)
{
	const char *fname;
	char *fpath, *fnamepart = NULL;
	off_t size = 0;
	alpm_handle_t *handle = newpkg->handle;
	int ret = 0;

	if(newpkg->origin != ALPM_PKG_FROM_SYNCDB) {
		newpkg->infolevel |= INFRQ_DSIZE;
		newpkg->download_size = 0;
		return 0;
	}

	ASSERT(newpkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1));
	fname = newpkg->filename;
	fpath = _alpm_filecache_find(handle, fname);

	/* downloaded file exists, so there's nothing to grab */
	if(fpath) {
		size = 0;
		goto finish;
	}

	CALLOC(fnamepart, strlen(fname) + 6, sizeof(char), return -1);
	sprintf(fnamepart, "%s.part", fname);
	fpath = _alpm_filecache_find(handle, fnamepart);
	if(fpath) {
		struct stat st;
		if(stat(fpath, &st) == 0) {
			/* subtract the size of the .part file */
			_alpm_log(handle, ALPM_LOG_DEBUG, "using (package - .part) size\n");
			size = newpkg->size - st.st_size;
			size = size < 0 ? 0 : size;
		}

		/* tell the caller that we have a partial */
		ret = 1;
	} else if(handle->deltaratio > 0.0) {
		off_t dltsize;

		dltsize = _alpm_shortest_delta_path(handle, newpkg->deltas,
				newpkg->filename, &newpkg->delta_path);

		if(newpkg->delta_path && (dltsize < newpkg->size * handle->deltaratio)) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "using delta size\n");
			size = dltsize;
		} else {
			_alpm_log(handle, ALPM_LOG_DEBUG, "using package size\n");
			size = newpkg->size;
			alpm_list_free(newpkg->delta_path);
			newpkg->delta_path = NULL;
		}
	} else {
		size = newpkg->size;
	}

finish:
	_alpm_log(handle, ALPM_LOG_DEBUG, "setting download size %jd for pkg %s\n",
			(intmax_t)size, newpkg->name);

	newpkg->infolevel |= INFRQ_DSIZE;
	newpkg->download_size = size;

	FREE(fpath);
	FREE(fnamepart);

	return ret;
}
Esempio n. 8
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;
}
Esempio n. 9
0
int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data)
{
	alpm_list_t *i;
	alpm_list_t *deltas = NULL;
	size_t numtargs, current = 0, replaces = 0;
	int errors;
	alpm_trans_t *trans = handle->trans;

	if(download_files(handle, &deltas)) {
		alpm_list_free(deltas);
		return -1;
	}

	if(validate_deltas(handle, deltas, data)) {
		alpm_list_free(deltas);
		return -1;
	}
	alpm_list_free(deltas);

	/* Check integrity of packages */
	numtargs = alpm_list_count(trans->add);
	EVENT(trans, ALPM_TRANS_EVT_INTEGRITY_START, NULL, NULL);

	errors = 0;

	for(i = trans->add; i; i = i->next, current++) {
		alpm_pkg_t *spkg = i->data;
		int percent = (current * 100) / numtargs;
		const char *filename;
		char *filepath;
		alpm_siglevel_t level;

		PROGRESS(trans, ALPM_TRANS_PROGRESS_INTEGRITY_START, "", percent,
				numtargs, current);
		if(spkg->origin == PKG_FROM_FILE) {
			continue; /* pkg_load() has been already called, this package is valid */
		}

		filename = alpm_pkg_get_filename(spkg);
		filepath = _alpm_filecache_find(handle, filename);
		alpm_db_t *sdb = alpm_pkg_get_db(spkg);
		level = alpm_db_get_siglevel(sdb);

		/* load the package file and replace pkgcache entry with it in the target list */
		/* TODO: alpm_pkg_get_db() will not work on this target anymore */
		_alpm_log(handle, ALPM_LOG_DEBUG,
				"replacing pkgcache entry with package file for target %s\n",
				spkg->name);
		alpm_pkg_t *pkgfile =_alpm_pkg_load_internal(handle, filepath, 1, spkg->md5sum,
				spkg->base64_sig, level);
		if(!pkgfile) {
			errors++;
			*data = alpm_list_add(*data, strdup(filename));
			FREE(filepath);
			continue;
		}
		FREE(filepath);
		pkgfile->reason = spkg->reason; /* copy over install reason */
		i->data = pkgfile;
		_alpm_pkg_free_trans(spkg); /* spkg has been removed from the target list */
	}

	PROGRESS(trans, ALPM_TRANS_PROGRESS_INTEGRITY_START, "", 100,
			numtargs, current);
	EVENT(trans, ALPM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL);


	if(errors) {
		RET_ERR(handle, ALPM_ERR_PKG_INVALID, -1);
	}

	if(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY) {
		return 0;
	}

	trans->state = STATE_COMMITING;

	replaces = alpm_list_count(trans->remove);

	/* fileconflict check */
	if(!(trans->flags & ALPM_TRANS_FLAG_FORCE)) {
		EVENT(trans, ALPM_TRANS_EVT_FILECONFLICTS_START, NULL, NULL);

		_alpm_log(handle, ALPM_LOG_DEBUG, "looking for file conflicts\n");
		alpm_list_t *conflict = _alpm_db_find_fileconflicts(handle,
				trans->add, trans->remove);
		if(conflict) {
			if(data) {
				*data = conflict;
			} else {
				alpm_list_free_inner(conflict, (alpm_list_fn_free)_alpm_fileconflict_free);
				alpm_list_free(conflict);
			}
			RET_ERR(handle, ALPM_ERR_FILE_CONFLICTS, -1);
		}

		EVENT(trans, ALPM_TRANS_EVT_FILECONFLICTS_DONE, NULL, NULL);
	}

	/* check available disk space */
	if(handle->checkspace) {
		EVENT(trans, ALPM_TRANS_EVT_DISKSPACE_START, NULL, NULL);

		_alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space\n");
		if(_alpm_check_diskspace(handle) == -1) {
			_alpm_log(handle, ALPM_LOG_ERROR, "%s\n", _("not enough free disk space"));
			return -1;
		}

		EVENT(trans, ALPM_TRANS_EVT_DISKSPACE_DONE, NULL, NULL);
	}

	/* remove conflicting and to-be-replaced packages */
	if(replaces) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "removing conflicting and to-be-replaced packages\n");
		/* we want the frontend to be aware of commit details */
		if(_alpm_remove_packages(handle) == -1) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not commit removal transaction\n"));
			return -1;
		}
	}

	/* install targets */
	_alpm_log(handle, ALPM_LOG_DEBUG, "installing packages\n");
	if(_alpm_upgrade_packages(handle) == -1) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not commit transaction\n"));
		return -1;
	}

	return 0;
}
Esempio n. 10
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;
}