diff options
Diffstat (limited to 'lib/libalpm')
31 files changed, 2388 insertions, 1405 deletions
| diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 3473a73a..da663cb5 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -25,20 +25,20 @@ libalpm_la_SOURCES = \  	alpm.h alpm.c \  	alpm_list.h alpm_list.c \  	backup.h backup.c \ -	be_files.c \ +	be_local.c \  	be_package.c \ -	cache.h cache.c \ +	be_sync.c \  	conflict.h conflict.c \  	db.h db.c \  	delta.h delta.c \  	deps.h deps.c \ +	diskspace.h diskspace.c \  	dload.h dload.c \  	error.c \  	graph.h \  	group.h group.c \  	handle.h handle.c \  	log.h log.c \ -	md5.h md5.c \  	package.h package.c \  	remove.h remove.c \  	sync.h sync.c \ @@ -46,6 +46,11 @@ libalpm_la_SOURCES = \  	util.h util.c \  	version.c +if !HAVE_LIBSSL +libalpm_la_SOURCES += \ +	md5.h md5.c +endif +  libalpm_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_INFO)  libalpm_la_LIBADD = $(LTLIBINTL) diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index f39a0ecf..b0b5a534 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -40,7 +40,6 @@  #include "alpm_list.h"  #include "trans.h"  #include "util.h" -#include "cache.h"  #include "log.h"  #include "backup.h"  #include "package.h" @@ -110,6 +109,31 @@ error:  	return(-1);  } +static int perform_extraction(struct archive *archive, +		struct archive_entry *entry, const char *filename, const char *origname) +{ +	int ret; +	const int archive_flags = ARCHIVE_EXTRACT_OWNER | +	                          ARCHIVE_EXTRACT_PERM | +	                          ARCHIVE_EXTRACT_TIME; + +	archive_entry_set_pathname(entry, filename); + +	ret = archive_read_extract(archive, entry, archive_flags); +	if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) { +		/* operation succeeded but a "non-critical" error was encountered */ +		_alpm_log(PM_LOG_WARNING, _("warning given when extracting %s (%s)\n"), +				origname, archive_error_string(archive)); +	} else if(ret != ARCHIVE_OK) { +		_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), +				origname, archive_error_string(archive)); +		alpm_logaction("error: could not extract %s (%s)\n", +				origname, archive_error_string(archive)); +		return(1); +	} +	return(0); +} +  static int extract_single_file(struct archive *archive,  		struct archive_entry *entry, pmpkg_t *newpkg, pmpkg_t *oldpkg,  		pmtrans_t *trans, pmdb_t *db) @@ -120,9 +144,6 @@ static int extract_single_file(struct archive *archive,  	int needbackup = 0, notouch = 0;  	char *hash_orig = NULL;  	char *entryname_orig = NULL; -	const int archive_flags = ARCHIVE_EXTRACT_OWNER | -	                          ARCHIVE_EXTRACT_PERM | -	                          ARCHIVE_EXTRACT_TIME;  	int errors = 0;  	entryname = archive_entry_pathname(entry); @@ -277,18 +298,10 @@ static int extract_single_file(struct archive *archive,  		int ret;  		snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); -		archive_entry_set_pathname(entry, checkfile); - -		ret = archive_read_extract(archive, entry, archive_flags); -		if(ret == ARCHIVE_WARN) { -			/* operation succeeded but a non-critical error was encountered */ -			_alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", -					entryname_orig, archive_error_string(archive)); -		} else if(ret != ARCHIVE_OK) { -			_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), -					entryname_orig, archive_error_string(archive)); -			alpm_logaction("error: could not extract %s (%s)\n", -					entryname_orig, archive_error_string(archive)); + +		ret = perform_extraction(archive, entry, checkfile, entryname_orig); +		if(ret == 1) { +			/* error */  			FREE(hash_orig);  			FREE(entryname_orig);  			return(1); @@ -430,18 +443,9 @@ static int extract_single_file(struct archive *archive,  			unlink(filename);  		} -		archive_entry_set_pathname(entry, filename); - -		ret = archive_read_extract(archive, entry, archive_flags); -		if(ret == ARCHIVE_WARN) { -			/* operation succeeded but a non-critical error was encountered */ -			_alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", -					entryname_orig, archive_error_string(archive)); -		} else if(ret != ARCHIVE_OK) { -			_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), -					entryname_orig, archive_error_string(archive)); -			alpm_logaction("error: could not extract %s (%s)\n", -					entryname_orig, archive_error_string(archive)); +		ret = perform_extraction(archive, entry, filename, entryname_orig); +		if(ret == 1) { +			/* error */  			FREE(entryname_orig);  			return(1);  		} @@ -498,7 +502,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  		oldpkg = _alpm_pkg_dup(local);  		/* make sure all infos are loaded because the database entry  		 * will be removed soon */ -		_alpm_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL); +		_alpm_local_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);  		EVENT(trans, PM_TRANS_EVT_UPGRADE_START, newpkg, oldpkg);  		_alpm_log(PM_LOG_DEBUG, "upgrading package %s-%s\n", @@ -544,7 +548,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  	/* prepare directory for database entries so permission are correct after  	   changelog/install script installation (FS#12263) */ -	if(_alpm_db_prepare(db, newpkg)) { +	if(_alpm_local_db_prepare(db, newpkg)) {  		alpm_logaction("error: could not create database entry %s-%s\n",  				alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));  		pm_errno = PM_ERR_DB_WRITE; @@ -556,6 +560,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  		struct archive *archive;  		struct archive_entry *entry;  		char cwd[PATH_MAX] = ""; +		int restore_cwd = 0;  		_alpm_log(PM_LOG_DEBUG, "extracting files\n"); @@ -579,11 +584,16 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  		/* save the cwd so we can restore it later */  		if(getcwd(cwd, PATH_MAX) == NULL) {  			_alpm_log(PM_LOG_ERROR, _("could not get current working directory\n")); -			cwd[0] = 0; +		} else { +			restore_cwd = 1;  		}  		/* libarchive requires this for extracting hard links */ -		chdir(handle->root); +		if(chdir(handle->root) != 0) { +			_alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno)); +			ret = -1; +			goto cleanup; +		}  		/* call PROGRESS once with 0 percent, as we sort-of skip that here */  		if(is_upgrade) { @@ -629,9 +639,9 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  		}  		archive_read_finish(archive); -		/* restore the old cwd is we have it */ -		if(strlen(cwd)) { -			chdir(cwd); +		/* restore the old cwd if we have it */ +		if(restore_cwd && chdir(cwd) != 0) { +			_alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));  		}  		if(errors) { @@ -656,7 +666,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  	_alpm_log(PM_LOG_DEBUG, "updating database\n");  	_alpm_log(PM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name); -	if(_alpm_db_write(db, newpkg, INFRQ_ALL)) { +	if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {  		_alpm_log(PM_LOG_ERROR, _("could not update database entry %s-%s\n"),  				alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));  		alpm_logaction("error: could not update database entry %s-%s\n", @@ -706,6 +716,7 @@ cleanup:  int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)  {  	int pkg_count, pkg_current; +	int skip_ldconfig = 0, ret = 0;  	alpm_list_t *targ;  	ALPM_LOG_FUNC; @@ -723,18 +734,28 @@ int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)  	/* loop through our package list adding/upgrading one at a time */  	for(targ = trans->add; targ; targ = targ->next) {  		if(handle->trans->state == STATE_INTERRUPTED) { -			return(0); +			return(ret);  		}  		pmpkg_t *newpkg = (pmpkg_t *)targ->data; -		commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db); +		if(commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db)) { +			/* something screwed up on the commit, abort the trans */ +			trans->state = STATE_INTERRUPTED; +			pm_errno = PM_ERR_TRANS_ABORT; +			/* running ldconfig at this point could possibly screw system */ +			skip_ldconfig = 1; +			ret = -1; +		} +  		pkg_current++;  	} -	/* run ldconfig if it exists */ -	_alpm_ldconfig(handle->root); +	if(!skip_ldconfig) { +		/* run ldconfig if it exists */ +		_alpm_ldconfig(handle->root); +	} -	return(0); +	return(ret);  }  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index 51b9e25b..3f9cfff3 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -23,6 +23,11 @@  #include "config.h" +/* connection caching setup */ +#ifdef HAVE_LIBFETCH +#include <fetch.h> +#endif +  /* libalpm */  #include "alpm.h"  #include "alpm_list.h" @@ -54,6 +59,10 @@ int SYMEXPORT alpm_initialize(void)  	bindtextdomain("libalpm", LOCALEDIR);  #endif +#ifdef HAVE_LIBFETCH +	fetchConnectionCacheInit(5, 1); +#endif +  	return(0);  } @@ -73,6 +82,10 @@ int SYMEXPORT alpm_release(void)  	_alpm_handle_free(handle);  	handle = NULL; +#ifdef HAVE_LIBFETCH +	fetchConnectionCacheClose(); +#endif +  	return(0);  } diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 33291325..08d02698 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -155,6 +155,9 @@ void alpm_option_set_arch(const char *arch);  int alpm_option_get_usedelta();  void alpm_option_set_usedelta(int usedelta); +int alpm_option_get_checkspace(); +void alpm_option_set_checkspace(int checkspace); +  pmdb_t *alpm_option_get_localdb();  alpm_list_t *alpm_option_get_syncdbs(); @@ -235,7 +238,7 @@ size_t alpm_pkg_changelog_read(void *ptr, size_t size,  /*int alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp);*/  int alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp);  int alpm_pkg_has_scriptlet(pmpkg_t *pkg); -int alpm_pkg_has_force(pmpkg_t *pkg); +int alpm_pkg_get_epoch(pmpkg_t *pkg);  off_t alpm_pkg_download_size(pmpkg_t *newpkg);  alpm_list_t *alpm_pkg_unused_deltas(pmpkg_t *pkg); @@ -368,6 +371,10 @@ typedef enum _pmtransevt_t {  	 * The repository's tree name is passed to the callback.  	 */  	PM_TRANS_EVT_RETRIEVE_START, +	/** Disk space usage will be computed for a package */ +	PM_TRANS_EVT_DISKSPACE_START, +	/** Disk space usage was computed for a package */ +	PM_TRANS_EVT_DISKSPACE_DONE,  } pmtransevt_t;  /*@}*/ @@ -386,7 +393,8 @@ typedef enum _pmtransprog_t {  	PM_TRANS_PROGRESS_ADD_START,  	PM_TRANS_PROGRESS_UPGRADE_START,  	PM_TRANS_PROGRESS_REMOVE_START, -	PM_TRANS_PROGRESS_CONFLICTS_START +	PM_TRANS_PROGRESS_CONFLICTS_START, +	PM_TRANS_PROGRESS_DISKSPACE_START,  } pmtransprog_t;  /* Transaction Event callback */ @@ -429,10 +437,9 @@ typedef enum _pmdepmod_t {  	PM_DEP_MOD_LT  } pmdepmod_t; -int alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep);  alpm_list_t *alpm_checkdeps(alpm_list_t *pkglist, int reversedeps,  		alpm_list_t *remove, alpm_list_t *upgrade); -alpm_list_t *alpm_deptest(pmdb_t *db, alpm_list_t *targets); +pmpkg_t *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring);  const char *alpm_miss_get_target(const pmdepmissing_t *miss);  pmdepend_t *alpm_miss_get_dep(pmdepmissing_t *miss); @@ -480,6 +487,7 @@ enum _pmerrno_t {  	PM_ERR_NOT_A_FILE,  	PM_ERR_NOT_A_DIR,  	PM_ERR_WRONG_ARGS, +	PM_ERR_DISK_SPACE,  	/* Interface */  	PM_ERR_HANDLE_NULL,  	PM_ERR_HANDLE_NOT_NULL, @@ -522,6 +530,7 @@ enum _pmerrno_t {  	PM_ERR_FILE_CONFLICTS,  	/* Misc */  	PM_ERR_RETRIEVE, +	PM_ERR_WRITE,  	PM_ERR_INVALID_REGEX,  	/* External library errors */  	PM_ERR_LIBARCHIVE, diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_local.c index c0b8b439..a5a7e996 100644 --- a/lib/libalpm/be_files.c +++ b/lib/libalpm/be_local.c @@ -1,8 +1,8 @@  /* - *  be_files.c + *  be_local.c   * - *  Copyright (c) 2006 by Christian Hamar <krics@linuxforum.hu> - *  Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> + *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify   *  it under the terms of the GNU General Public License as published by @@ -40,317 +40,340 @@  /* libalpm */  #include "db.h"  #include "alpm_list.h" -#include "cache.h"  #include "log.h"  #include "util.h"  #include "alpm.h"  #include "handle.h"  #include "package.h" -#include "delta.h" +#include "group.h"  #include "deps.h"  #include "dload.h" -static int checkdbdir(pmdb_t *db) -{ -	struct stat buf; -	const char *path = _alpm_db_path(db); +#define LAZY_LOAD(info, errret) \ +	do { \ +		ALPM_LOG_FUNC; \ +		ASSERT(handle != NULL, return(errret)); \ +		ASSERT(pkg != NULL, return(errret)); \ +		if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & info)) { \ +			_alpm_local_db_read(pkg->origin_data.db, pkg, info); \ +		} \ +	} while(0) -	if(stat(path, &buf) != 0) { -		_alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n", -				path); -		if(_alpm_makepath(path) != 0) { -			RET_ERR(PM_ERR_SYSTEM, -1); -		} -	} else if(!S_ISDIR(buf.st_mode)) { -		_alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path); -		if(unlink(path) != 0 || _alpm_makepath(path) != 0) { -			RET_ERR(PM_ERR_SYSTEM, -1); -		} -	} -	return(0); -} -/* create list of directories in db */ -static int dirlist_from_tar(const char *archive, alpm_list_t **dirlist) +/* Cache-specific accessor functions. These implementations allow for lazy + * loading by the files backend when a data member is actually needed + * rather than loading all pieces of information when the package is first + * initialized. + */ + +const char *_cache_get_filename(pmpkg_t *pkg)  { -	struct archive *_archive; -	struct archive_entry *entry; +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->filename; +} -	if((_archive = archive_read_new()) == NULL) -		RET_ERR(PM_ERR_LIBARCHIVE, -1); +const char *_cache_get_name(pmpkg_t *pkg) +{ +	ASSERT(pkg != NULL, return(NULL)); +	return pkg->name; +} -	archive_read_support_compression_all(_archive); -	archive_read_support_format_all(_archive); +static const char *_cache_get_version(pmpkg_t *pkg) +{ +	ASSERT(pkg != NULL, return(NULL)); +	return pkg->version; +} -	if(archive_read_open_filename(_archive, archive, -				ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { -		_alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive, -				archive_error_string(_archive)); -		RET_ERR(PM_ERR_PKG_OPEN, -1); -	} +static const char *_cache_get_desc(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->desc; +} -	while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { -		const struct stat *st; -		const char *entryname; /* the name of the file in the archive */ +const char *_cache_get_url(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->url; +} -		st = archive_entry_stat(entry); -		entryname = archive_entry_pathname(entry); +time_t _cache_get_builddate(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, 0); +	return pkg->builddate; +} -		if(S_ISDIR(st->st_mode)) { -			char *name = strdup(entryname); -			*dirlist = alpm_list_add(*dirlist, name); -		} -	} -	archive_read_finish(_archive); +time_t _cache_get_installdate(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, 0); +	return pkg->installdate; +} -	*dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); -	return(0); +const char *_cache_get_packager(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->packager;  } -/* create list of directories in db */ -static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist) +const char *_cache_get_md5sum(pmpkg_t *pkg)  { -	DIR *dbdir; -	struct dirent *ent = NULL; -	struct stat sbuf; -	char path[PATH_MAX]; +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->md5sum; +} -	dbdir = opendir(syncdbpath); -	if (dbdir != NULL) { -		while((ent = readdir(dbdir)) != NULL) { -			char *name = ent->d_name; -			size_t len; -			char *entry; +const char *_cache_get_arch(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->arch; +} -			if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { -				continue; -			} +off_t _cache_get_size(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->size; +} -			/* stat the entry, make sure it's a directory */ -			snprintf(path, PATH_MAX, "%s%s", syncdbpath, name); -			if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) { -				continue; -			} +off_t _cache_get_isize(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->isize; +} -			len = strlen(name); -			MALLOC(entry, len + 2, RET_ERR(PM_ERR_MEMORY, -1)); -			strcpy(entry, name); -			entry[len] = '/'; -			entry[len+1] = '\0'; -			*dirlist = alpm_list_add(*dirlist, entry); -		} -		closedir(dbdir); -	} +pmpkgreason_t _cache_get_reason(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->reason; +} -	*dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); -	return(0); +alpm_list_t *_cache_get_licenses(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->licenses;  } -/* remove old directories from dbdir */ -static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist) +alpm_list_t *_cache_get_groups(pmpkg_t *pkg)  { -	alpm_list_t *i; -	for (i = dirlist; i; i = i->next) { -		const char *name = i->data; -		char *dbdir; -		size_t len = strlen(syncdbpath) + strlen(name) + 2; -		MALLOC(dbdir, len, RET_ERR(PM_ERR_MEMORY, -1)); -		snprintf(dbdir, len, "%s%s", syncdbpath, name); -		_alpm_log(PM_LOG_DEBUG, "removing: %s\n", dbdir); -		if(_alpm_rmrf(dbdir) != 0) { -			_alpm_log(PM_LOG_ERROR, _("could not remove database directory %s\n"), dbdir); -			free(dbdir); -			RET_ERR(PM_ERR_DB_REMOVE, -1); -		} -		free(dbdir); -	} -	return(0); +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->groups;  } -/** Update a package database - * - * An update of the package database \a db will be attempted. Unless - * \a force is true, the update will only be performed if the remote - * database was modified since the last update. - * - * A transaction is necessary for this operation, in order to obtain a - * database lock. During this transaction the front-end will be informed - * of the download progress of the database via the download callback. - * - * Example: - * @code - * pmdb_t *db; - * int result; - * db = alpm_list_getdata(alpm_option_get_syncdbs()); - * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) { - *     result = alpm_db_update(0, db); - *     alpm_trans_release(); - * - *     if(result > 0) { - *	       printf("Unable to update database: %s\n", alpm_strerrorlast()); - *     } else if(result < 0) { - *         printf("Database already up to date\n"); - *     } else { - *         printf("Database updated\n"); - *     } - * } - * @endcode - * - * @ingroup alpm_databases - * @note After a successful update, the \link alpm_db_get_pkgcache() - * package cache \endlink will be invalidated - * @param force if true, then forces the update, otherwise update only in case - * the database isn't up to date - * @param db pointer to the package database to update - * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up - * to date - */ -int SYMEXPORT alpm_db_update(int force, pmdb_t *db) +int _cache_get_epoch(pmpkg_t *pkg)  { -	char *dbfile, *dbfilepath; -	const char *dbpath, *syncdbpath; -	alpm_list_t *newdirlist = NULL, *olddirlist = NULL; -	alpm_list_t *onlynew = NULL, *onlyold = NULL; -	size_t len; -	int ret; +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->epoch; +} +int _cache_has_scriptlet(pmpkg_t *pkg) +{  	ALPM_LOG_FUNC;  	/* Sanity checks */ -	ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); -	ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1)); -	/* Verify we are in a transaction.  This is done _mainly_ because we need a DB -	 * lock - if we update without a db lock, we may kludge some other pacman -	 * process that _has_ a lock. -	 */ -	ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); -	ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1)); - -	if(!alpm_list_find_ptr(handle->dbs_sync, db)) { -		RET_ERR(PM_ERR_DB_NOT_FOUND, -1); +	ASSERT(handle != NULL, return(-1)); +	ASSERT(pkg != NULL, return(-1)); + +	if(!(pkg->infolevel & INFRQ_SCRIPTLET)) { +		_alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);  	} +	return pkg->scriptlet; +} -	len = strlen(db->treename) + strlen(DBEXT) + 1; -	MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1)); -	sprintf(dbfile, "%s" DBEXT, db->treename); +alpm_list_t *_cache_get_depends(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->depends; +} -	dbpath = alpm_option_get_dbpath(); +alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->optdepends; +} -	ret = _alpm_download_single_file(dbfile, db->servers, dbpath, force); -	free(dbfile); +alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->conflicts; +} -	if(ret == 1) { -		/* files match, do nothing */ -		pm_errno = 0; -		return(1); -	} else if(ret == -1) { -		/* pm_errno was set by the download code */ -		_alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast()); -		return(-1); -	} +alpm_list_t *_cache_get_provides(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->provides; +} -	syncdbpath = _alpm_db_path(db); - -	/* form the path to the db location */ -	len = strlen(dbpath) + strlen(db->treename) + strlen(DBEXT) + 1; -	MALLOC(dbfilepath, len, RET_ERR(PM_ERR_MEMORY, -1)); -	sprintf(dbfilepath, "%s%s" DBEXT, dbpath, db->treename); - -	if(force) { -		/* if forcing update, remove the old dir and extract the db */ -		if(_alpm_rmrf(syncdbpath) != 0) { -			_alpm_log(PM_LOG_ERROR, _("could not remove database %s\n"), db->treename); -			RET_ERR(PM_ERR_DB_REMOVE, -1); -		} else { -			_alpm_log(PM_LOG_DEBUG, "database dir %s removed\n", _alpm_db_path(db)); -		} -	} else { -		/* if not forcing, only remove and extract what is necessary */ -		ret = dirlist_from_tar(dbfilepath, &newdirlist); -		if(ret) { -			goto cleanup; -		} -		ret = dirlist_from_fs(syncdbpath, &olddirlist); -		if(ret) { -			goto cleanup; -		} +alpm_list_t *_cache_get_replaces(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->replaces; +} -		alpm_list_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew); +alpm_list_t *_cache_get_files(pmpkg_t *pkg) +{ +	ALPM_LOG_FUNC; -		ret = remove_olddir(syncdbpath, onlyold); -		if(ret) { -			goto cleanup; -		} +	/* Sanity checks */ +	ASSERT(handle != NULL, return(NULL)); +	ASSERT(pkg != NULL, return(NULL)); + +	if(pkg->origin == PKG_FROM_LOCALDB +		 && !(pkg->infolevel & INFRQ_FILES)) { +		_alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);  	} +	return pkg->files; +} -	/* Cache needs to be rebuilt */ -	_alpm_db_free_pkgcache(db); +alpm_list_t *_cache_get_backup(pmpkg_t *pkg) +{ +	ALPM_LOG_FUNC; -	checkdbdir(db); -	ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0); +	/* Sanity checks */ +	ASSERT(handle != NULL, return(NULL)); +	ASSERT(pkg != NULL, return(NULL)); -cleanup: -	FREELIST(newdirlist); -	FREELIST(olddirlist); -	alpm_list_free(onlynew); -	alpm_list_free(onlyold); +	if(pkg->origin == PKG_FROM_LOCALDB +		 && !(pkg->infolevel & INFRQ_FILES)) { +		_alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); +	} +	return pkg->backup; +} -	free(dbfilepath); +/** + * Open a package changelog for reading. Similar to fopen in functionality, + * except that the returned 'file stream' is from the database. + * @param pkg the package (from db) to read the changelog + * @return a 'file stream' to the package changelog + */ +void *_cache_changelog_open(pmpkg_t *pkg) +{ +	ALPM_LOG_FUNC; -	if(ret) { -		RET_ERR(PM_ERR_SYSTEM, -1); -	} +	/* Sanity checks */ +	ASSERT(handle != NULL, return(NULL)); +	ASSERT(pkg != NULL, return(NULL)); + +	char clfile[PATH_MAX]; +	snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog", +			alpm_option_get_dbpath(), +			alpm_db_get_name(alpm_pkg_get_db(pkg)), +			alpm_pkg_get_name(pkg), +			alpm_pkg_get_version(pkg)); +	return fopen(clfile, "r"); +} -	return(0); +/** + * Read data from an open changelog 'file stream'. Similar to fread in + * functionality, this function takes a buffer and amount of data to read. + * @param ptr a buffer to fill with raw changelog data + * @param size the size of the buffer + * @param pkg the package that the changelog is being read from + * @param fp a 'file stream' to the package changelog + * @return the number of characters read, or 0 if there is no more data + */ +size_t _cache_changelog_read(void *ptr, size_t size, +		const pmpkg_t *pkg, const void *fp) +{ +	return ( fread(ptr, 1, size, (FILE*)fp) );  } +/* +int _cache_changelog_feof(const pmpkg_t *pkg, void *fp) +{ +	return( feof((FILE*)fp) ); +} +*/ + +/** + * Close a package changelog for reading. Similar to fclose in functionality, + * except that the 'file stream' is from the database. + * @param pkg the package that the changelog was read from + * @param fp a 'file stream' to the package changelog + * @return whether closing the package changelog stream was successful + */ +int _cache_changelog_close(const pmpkg_t *pkg, void *fp) +{ +	return( fclose((FILE*)fp) ); +} + +/* We're cheating, local packages can't have deltas anyway. */ +alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg); -static int splitname(const char *target, pmpkg_t *pkg) +/** The local database operations struct. Get package fields through + * lazy accessor methods that handle any backend loading and caching + * logic. + */ +static struct pkg_operations local_pkg_ops = { +	.get_filename    = _cache_get_filename, +	.get_name        = _cache_get_name, +	.get_version     = _cache_get_version, +	.get_desc        = _cache_get_desc, +	.get_url         = _cache_get_url, +	.get_builddate   = _cache_get_builddate, +	.get_installdate = _cache_get_installdate, +	.get_packager    = _cache_get_packager, +	.get_md5sum      = _cache_get_md5sum, +	.get_arch        = _cache_get_arch, +	.get_size        = _cache_get_size, +	.get_isize       = _cache_get_isize, +	.get_reason      = _cache_get_reason, +	.get_epoch       = _cache_get_epoch, +	.has_scriptlet   = _cache_has_scriptlet, +	.get_licenses    = _cache_get_licenses, +	.get_groups      = _cache_get_groups, +	.get_depends     = _cache_get_depends, +	.get_optdepends  = _cache_get_optdepends, +	.get_conflicts   = _cache_get_conflicts, +	.get_provides    = _cache_get_provides, +	.get_replaces    = _cache_get_replaces, +	.get_deltas      = _pkg_get_deltas, +	.get_files       = _cache_get_files, +	.get_backup      = _cache_get_backup, + +	.changelog_open  = _cache_changelog_open, +	.changelog_read  = _cache_changelog_read, +	.changelog_close = _cache_changelog_close, +}; + +static int checkdbdir(pmdb_t *db)  { -	/* the format of a db entry is as follows: -	 *    package-version-rel/ -	 * package name can contain hyphens, so parse from the back- go back -	 * two hyphens and we have split the version from the name. -	 */ -	char *tmp, *p, *q; +	struct stat buf; +	const char *path = _alpm_db_path(db); -	if(target == NULL || pkg == NULL) { -		return(-1); -	} -	STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1)); -	p = tmp + strlen(tmp); - -	/* do the magic parsing- find the beginning of the version string -	 * by doing two iterations of same loop to lop off two hyphens */ -	for(q = --p; *q && *q != '-'; q--); -	for(p = --q; *p && *p != '-'; p--); -	if(*p != '-' || p == tmp) { -		return(-1); +	if(stat(path, &buf) != 0) { +		_alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n", +				path); +		if(_alpm_makepath(path) != 0) { +			RET_ERR(PM_ERR_SYSTEM, -1); +		} +	} else if(!S_ISDIR(buf.st_mode)) { +		_alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path); +		if(unlink(path) != 0 || _alpm_makepath(path) != 0) { +			RET_ERR(PM_ERR_SYSTEM, -1); +		}  	} +	return(0); +} -	/* copy into fields and return */ -	if(pkg->version) { -		FREE(pkg->version); -	} -	STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1)); -	/* insert a terminator at the end of the name (on hyphen)- then copy it */ -	*p = '\0'; -	if(pkg->name) { -		FREE(pkg->name); +static int is_dir(const char *path, struct dirent *entry) +{ +#ifdef HAVE_STRUCT_DIRENT_D_TYPE +	return(entry->d_type == DT_DIR); +#else +	char buffer[PATH_MAX]; +	snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name); + +	struct stat sbuf; +	if (!stat(buffer, &sbuf)) { +		return(S_ISDIR(sbuf.st_mode));  	} -	STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1)); -	free(tmp);  	return(0); +#endif  } -int _alpm_db_populate(pmdb_t *db) +static int local_db_populate(pmdb_t *db)  {  	int count = 0;  	struct dirent *ent = NULL; -	struct stat sbuf; -	char path[PATH_MAX];  	const char *dbpath;  	DIR *dbdir; @@ -359,20 +382,22 @@ int _alpm_db_populate(pmdb_t *db)  	ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));  	dbpath = _alpm_db_path(db); +	if(dbpath == NULL) { +		return(-1); +	}  	dbdir = opendir(dbpath);  	if(dbdir == NULL) {  		return(0);  	}  	while((ent = readdir(dbdir)) != NULL) {  		const char *name = ent->d_name; +  		pmpkg_t *pkg;  		if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {  			continue;  		} -		/* stat the entry, make sure it's a directory */ -		snprintf(path, PATH_MAX, "%s%s", dbpath, name); -		if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) { +		if(!is_dir(dbpath, ent)) {  			continue;  		} @@ -382,7 +407,7 @@ int _alpm_db_populate(pmdb_t *db)  			return(-1);  		}  		/* split the db entry name */ -		if(splitname(name, pkg) != 0) { +		if(_alpm_splitname(name, pkg) != 0) {  			_alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),  					name);  			_alpm_pkg_free(pkg); @@ -397,12 +422,15 @@ int _alpm_db_populate(pmdb_t *db)  		}  		/* explicitly read with only 'BASE' data, accessors will handle the rest */ -		if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) { +		if(_alpm_local_db_read(db, pkg, INFRQ_BASE) == -1) {  			_alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);  			_alpm_pkg_free(pkg);  			continue;  		} -		pkg->origin = PKG_FROM_CACHE; + +		pkg->origin = PKG_FROM_LOCALDB; +		pkg->ops = &local_pkg_ops; +  		pkg->origin_data.db = db;  		/* add to the collection */  		_alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", @@ -430,12 +458,12 @@ static char *get_pkgpath(pmdb_t *db, pmpkg_t *info)  	return(pkgpath);  } -int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) + +int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  {  	FILE *fp = NULL;  	char path[PATH_MAX]; -	char line[513]; -	int	sline = sizeof(line)-1; +	char line[1024];  	char *pkgpath = NULL;  	ALPM_LOG_FUNC; @@ -445,7 +473,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  	}  	if(info == NULL || info->name == NULL || info->version == NULL) { -		_alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n"); +		_alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_local_db_read, skipping\n");  		return(-1);  	} @@ -467,7 +495,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  			info->name, inforeq);  	/* clear out 'line', to be certain - and to make valgrind happy */ -	memset(line, 0, sline+1); +	memset(line, 0, sizeof(line));  	pkgpath = get_pkgpath(db, info); @@ -486,12 +514,12 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  			goto error;  		}  		while(!feof(fp)) { -			if(fgets(line, 256, fp) == NULL) { +			if(fgets(line, sizeof(line), fp) == NULL) {  				break;  			}  			_alpm_strtrim(line);  			if(strcmp(line, "%NAME%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				if(strcmp(_alpm_strtrim(line), info->name) != 0) { @@ -499,47 +527,42 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  								"mismatch on package %s\n"), db->treename, info->name);  				}  			} else if(strcmp(line, "%VERSION%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				if(strcmp(_alpm_strtrim(line), info->version) != 0) {  					_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "  								"mismatch on package %s\n"), db->treename, info->name);  				} -			} else if(strcmp(line, "%FILENAME%") == 0) { -				if(fgets(line, sline, fp) == NULL) { -					goto error; -				} -				STRDUP(info->filename, _alpm_strtrim(line), goto error);  			} else if(strcmp(line, "%DESC%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				STRDUP(info->desc, _alpm_strtrim(line), goto error);  			} else if(strcmp(line, "%GROUPS%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {  					char *linedup;  					STRDUP(linedup, _alpm_strtrim(line), goto error);  					info->groups = alpm_list_add(info->groups, linedup);  				}  			} else if(strcmp(line, "%URL%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				STRDUP(info->url, _alpm_strtrim(line), goto error);  			} else if(strcmp(line, "%LICENSE%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {  					char *linedup;  					STRDUP(linedup, _alpm_strtrim(line), goto error);  					info->licenses = alpm_list_add(info->licenses, linedup);  				}  			} else if(strcmp(line, "%ARCH%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				STRDUP(info->arch, _alpm_strtrim(line), goto error);  			} else if(strcmp(line, "%BUILDDATE%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				_alpm_strtrim(line); @@ -555,7 +578,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  					info->builddate = atol(line);  				}  			} else if(strcmp(line, "%INSTALLDATE%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				_alpm_strtrim(line); @@ -571,51 +594,67 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  					info->installdate = atol(line);  				}  			} else if(strcmp(line, "%PACKAGER%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				STRDUP(info->packager, _alpm_strtrim(line), goto error);  			} else if(strcmp(line, "%REASON%") == 0) { -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line)); -			} else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) { +			} else if(strcmp(line, "%SIZE%") == 0) {  				/* NOTE: the CSIZE and SIZE fields both share the "size" field  				 *       in the pkginfo_t struct.  This can be done b/c CSIZE  				 *       is currently only used in sync databases, and SIZE is  				 *       only used in local databases.  				 */ -				if(fgets(line, sline, fp) == NULL) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				}  				info->size = atol(_alpm_strtrim(line)); -				/* also store this value to isize if isize is unset */ -				if(info->isize == 0) { -					info->isize = info->size; +				/* also store this value to isize */ +				info->isize = info->size; +			} else if(strcmp(line, "%REPLACES%") == 0) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					info->replaces = alpm_list_add(info->replaces, linedup);  				} -			} else if(strcmp(line, "%ISIZE%") == 0) { -				/* ISIZE (installed size) tag only appears in sync repositories, -				 * not the local one. */ -				if(fgets(line, sline, fp) == NULL) { +			} else if(strcmp(line, "%EPOCH%") == 0) { +				if(fgets(line, sizeof(line), fp) == NULL) {  					goto error;  				} -				info->isize = atol(_alpm_strtrim(line)); -			} else if(strcmp(line, "%MD5SUM%") == 0) { -				/* MD5SUM tag only appears in sync repositories, -				 * not the local one. */ -				if(fgets(line, sline, fp) == NULL) { -					goto error; +				info->epoch = atoi(_alpm_strtrim(line)); +			} else if(strcmp(line, "%FORCE%") == 0) { +				/* For backward compatibility, treat force as a non-zero epoch +				 * but only if we didn't already have a known epoch value. */ +				if(!info->epoch) { +					info->epoch = 1;  				} -				STRDUP(info->md5sum, _alpm_strtrim(line), goto error); -			} else if(strcmp(line, "%REPLACES%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { +			} else if(strcmp(line, "%DEPENDS%") == 0) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { +					pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line)); +					info->depends = alpm_list_add(info->depends, dep); +				} +			} else if(strcmp(line, "%OPTDEPENDS%") == 0) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {  					char *linedup;  					STRDUP(linedup, _alpm_strtrim(line), goto error); -					info->replaces = alpm_list_add(info->replaces, linedup); +					info->optdepends = alpm_list_add(info->optdepends, linedup); +				} +			} else if(strcmp(line, "%CONFLICTS%") == 0) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					info->conflicts = alpm_list_add(info->conflicts, linedup); +				} +			} else if(strcmp(line, "%PROVIDES%") == 0) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					info->provides = alpm_list_add(info->provides, linedup);  				} -			} else if(strcmp(line, "%FORCE%") == 0) { -				info->force = 1;  			}  		}  		fclose(fp); @@ -629,16 +668,16 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  			_alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));  			goto error;  		} -		while(fgets(line, 256, fp)) { +		while(fgets(line, sizeof(line), fp)) {  			_alpm_strtrim(line);  			if(strcmp(line, "%FILES%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {  					char *linedup;  					STRDUP(linedup, _alpm_strtrim(line), goto error);  					info->files = alpm_list_add(info->files, linedup);  				}  			} else if(strcmp(line, "%BACKUP%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { +				while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {  					char *linedup;  					STRDUP(linedup, _alpm_strtrim(line), goto error);  					info->backup = alpm_list_add(info->backup, linedup); @@ -649,66 +688,6 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  		fp = NULL;  	} -	/* DEPENDS */ -	if(inforeq & INFRQ_DEPENDS) { -		snprintf(path, PATH_MAX, "%sdepends", pkgpath); -		if((fp = fopen(path, "r")) == NULL) { -			_alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); -			goto error; -		} -		while(!feof(fp)) { -			fgets(line, 255, fp); -			_alpm_strtrim(line); -			if(strcmp(line, "%DEPENDS%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { -					pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line)); -					info->depends = alpm_list_add(info->depends, dep); -				} -			} else if(strcmp(line, "%OPTDEPENDS%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { -					char *linedup; -					STRDUP(linedup, _alpm_strtrim(line), goto error); -					info->optdepends = alpm_list_add(info->optdepends, linedup); -				} -			} else if(strcmp(line, "%CONFLICTS%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { -					char *linedup; -					STRDUP(linedup, _alpm_strtrim(line), goto error); -					info->conflicts = alpm_list_add(info->conflicts, linedup); -				} -			} else if(strcmp(line, "%PROVIDES%") == 0) { -				while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { -					char *linedup; -					STRDUP(linedup, _alpm_strtrim(line), goto error); -					info->provides = alpm_list_add(info->provides, linedup); -				} -			} -		} -		fclose(fp); -		fp = NULL; -	} - -	/* DELTAS */ -	if(inforeq & INFRQ_DELTAS) { -		snprintf(path, PATH_MAX, "%sdeltas", pkgpath); -		if((fp = fopen(path, "r"))) { -			while(!feof(fp)) { -				fgets(line, 255, fp); -				_alpm_strtrim(line); -				if(strcmp(line, "%DELTAS%") == 0) { -					while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { -						pmdelta_t *delta = _alpm_delta_parse(line); -						if(delta) { -							info->deltas = alpm_list_add(info->deltas, delta); -						} -					} -				} -			} -			fclose(fp); -			fp = NULL; -		} -	} -  	/* INSTALL */  	if(inforeq & INFRQ_SCRIPTLET) {  		snprintf(path, PATH_MAX, "%sinstall", pkgpath); @@ -731,7 +710,7 @@ error:  	return(-1);  } -int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info) +int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info)  {  	mode_t oldmask;  	int retval = 0; @@ -755,14 +734,13 @@ int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info)  	return(retval);  } -int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) +int _alpm_local_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  {  	FILE *fp = NULL;  	char path[PATH_MAX];  	mode_t oldmask;  	alpm_list_t *lp = NULL;  	int retval = 0; -	int local = 0;  	char *pkgpath = NULL;  	ALPM_LOG_FUNC; @@ -776,8 +754,8 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  	/* make sure we have a sane umask */  	oldmask = umask(0022); -	if(strcmp(db->treename, "local") == 0) { -		local = 1; +	if(strcmp(db->treename, "local") != 0) { +		return(-1);  	}  	/* DESC */ @@ -810,102 +788,45 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  			}  			fprintf(fp, "\n");  		} -		if(local) { -			if(info->force) { -				fprintf(fp, "%%EPOCH%%\n" -						"1\n\n"); -			} -			if(info->url) { -				fprintf(fp, "%%URL%%\n" -								"%s\n\n", info->url); -			} -			if(info->licenses) { -				fputs("%LICENSE%\n", fp); -				for(lp = info->licenses; lp; lp = lp->next) { -					fprintf(fp, "%s\n", (char *)lp->data); -				} -				fprintf(fp, "\n"); -			} -			if(info->arch) { -				fprintf(fp, "%%ARCH%%\n" -								"%s\n\n", info->arch); -			} -			if(info->builddate) { -				fprintf(fp, "%%BUILDDATE%%\n" -								"%ld\n\n", info->builddate); -			} -			if(info->installdate) { -				fprintf(fp, "%%INSTALLDATE%%\n" -								"%ld\n\n", info->installdate); -			} -			if(info->packager) { -				fprintf(fp, "%%PACKAGER%%\n" -								"%s\n\n", info->packager); -			} -			if(info->isize) { -				/* only write installed size, csize is irrelevant once installed */ -				fprintf(fp, "%%SIZE%%\n" -								"%jd\n\n", (intmax_t)info->isize); -			} -			if(info->reason) { -				fprintf(fp, "%%REASON%%\n" -								"%u\n\n", info->reason); -			} -		} else { -			if(info->size) { -				fprintf(fp, "%%CSIZE%%\n" -								"%jd\n\n", (intmax_t)info->size); -			} -			if(info->isize) { -				fprintf(fp, "%%ISIZE%%\n" -								"%jd\n\n", (intmax_t)info->isize); -			} -			if(info->md5sum) { -				fprintf(fp, "%%MD5SUM%%\n" -								"%s\n\n", info->md5sum); -			} +		if(info->epoch) { +			fprintf(fp, "%%EPOCH%%\n" +							"%d\n\n", info->epoch);  		} -		fclose(fp); -		fp = NULL; -	} - -	/* FILES */ -	if(local && (inforeq & INFRQ_FILES)) { -		_alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n", -				info->name, info->version); -		snprintf(path, PATH_MAX, "%sfiles", pkgpath); -		if((fp = fopen(path, "w")) == NULL) { -			_alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); -			retval = -1; -			goto cleanup; +		if(info->url) { +			fprintf(fp, "%%URL%%\n" +							"%s\n\n", info->url);  		} -		if(info->files) { -			fprintf(fp, "%%FILES%%\n"); -			for(lp = info->files; lp; lp = lp->next) { +		if(info->licenses) { +			fputs("%LICENSE%\n", fp); +			for(lp = info->licenses; lp; lp = lp->next) {  				fprintf(fp, "%s\n", (char *)lp->data);  			}  			fprintf(fp, "\n");  		} -		if(info->backup) { -			fprintf(fp, "%%BACKUP%%\n"); -			for(lp = info->backup; lp; lp = lp->next) { -				fprintf(fp, "%s\n", (char *)lp->data); -			} -			fprintf(fp, "\n"); +		if(info->arch) { +			fprintf(fp, "%%ARCH%%\n" +							"%s\n\n", info->arch);  		} -		fclose(fp); -		fp = NULL; -	} - -	/* DEPENDS */ -	if(inforeq & INFRQ_DEPENDS) { -		_alpm_log(PM_LOG_DEBUG, "writing %s-%s DEPENDS information back to db\n", -			info->name, info->version); -		snprintf(path, PATH_MAX, "%sdepends", pkgpath); -		if((fp = fopen(path, "w")) == NULL) { -			_alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); -			retval = -1; -			goto cleanup; +		if(info->builddate) { +			fprintf(fp, "%%BUILDDATE%%\n" +							"%ld\n\n", info->builddate); +		} +		if(info->installdate) { +			fprintf(fp, "%%INSTALLDATE%%\n" +							"%ld\n\n", info->installdate); +		} +		if(info->packager) { +			fprintf(fp, "%%PACKAGER%%\n" +							"%s\n\n", info->packager); +		} +		if(info->isize) { +			/* only write installed size, csize is irrelevant once installed */ +			fprintf(fp, "%%SIZE%%\n" +							"%jd\n\n", (intmax_t)info->isize); +		} +		if(info->reason) { +			fprintf(fp, "%%REASON%%\n" +							"%u\n\n", info->reason);  		}  		if(info->depends) {  			fputs("%DEPENDS%\n", fp); @@ -937,6 +858,35 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)  			}  			fprintf(fp, "\n");  		} + +		fclose(fp); +		fp = NULL; +	} + +	/* FILES */ +	if(inforeq & INFRQ_FILES) { +		_alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n", +				info->name, info->version); +		snprintf(path, PATH_MAX, "%sfiles", pkgpath); +		if((fp = fopen(path, "w")) == NULL) { +			_alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); +			retval = -1; +			goto cleanup; +		} +		if(info->files) { +			fprintf(fp, "%%FILES%%\n"); +			for(lp = info->files; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			fprintf(fp, "\n"); +		} +		if(info->backup) { +			fprintf(fp, "%%BACKUP%%\n"); +			for(lp = info->backup; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			fprintf(fp, "\n"); +		}  		fclose(fp);  		fp = NULL;  	} @@ -955,7 +905,7 @@ cleanup:  	return(retval);  } -int _alpm_db_remove(pmdb_t *db, pmpkg_t *info) +int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info)  {  	int ret = 0;  	char *pkgpath = NULL; @@ -976,4 +926,33 @@ int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)  	return(ret);  } +struct db_operations local_db_ops = { +	.populate         = local_db_populate, +	.unregister       = _alpm_db_unregister, +}; + +pmdb_t *_alpm_db_register_local(void) +{ +	pmdb_t *db; + +	ALPM_LOG_FUNC; + +	if(handle->db_local != NULL) { +		_alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n")); +		RET_ERR(PM_ERR_DB_NOT_NULL, NULL); +	} + +	_alpm_log(PM_LOG_DEBUG, "registering local database\n"); + +	db = _alpm_db_new("local", 1); +	db->ops = &local_db_ops; +	if(db == NULL) { +		RET_ERR(PM_ERR_DB_CREATE, NULL); +	} + +	handle->db_local = db; +	return(db); +} + +  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index ff266ae8..32ec9934 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -26,6 +26,7 @@  #include <limits.h>  #include <ctype.h>  #include <locale.h> /* setlocale */ +#include <errno.h>  /* libarchive */  #include <archive.h> @@ -39,6 +40,113 @@  #include "deps.h" /* _alpm_splitdep */  /** + * Open a package changelog for reading. Similar to fopen in functionality, + * except that the returned 'file stream' is from an archive. + * @param pkg the package (file) to read the changelog + * @return a 'file stream' to the package changelog + */ +void *_package_changelog_open(pmpkg_t *pkg) +{ +	ALPM_LOG_FUNC; + +	ASSERT(pkg != NULL, return(NULL)); + +	struct archive *archive = NULL; +	struct archive_entry *entry; +	const char *pkgfile = pkg->origin_data.file; + +	if((archive = archive_read_new()) == NULL) { +		RET_ERR(PM_ERR_LIBARCHIVE, NULL); +	} + +	archive_read_support_compression_all(archive); +	archive_read_support_format_all(archive); + +	if (archive_read_open_filename(archive, pkgfile, +				ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { +		RET_ERR(PM_ERR_PKG_OPEN, NULL); +	} + +	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { +		const char *entry_name = archive_entry_pathname(entry); + +		if(strcmp(entry_name, ".CHANGELOG") == 0) { +			return(archive); +		} +	} +	/* we didn't find a changelog */ +	archive_read_finish(archive); +	errno = ENOENT; + +	return(NULL); +} + +/** + * Read data from an open changelog 'file stream'. Similar to fread in + * functionality, this function takes a buffer and amount of data to read. + * @param ptr a buffer to fill with raw changelog data + * @param size the size of the buffer + * @param pkg the package that the changelog is being read from + * @param fp a 'file stream' to the package changelog + * @return the number of characters read, or 0 if there is no more data + */ +size_t _package_changelog_read(void *ptr, size_t size, +		const pmpkg_t *pkg, const void *fp) +{ +	ssize_t sret = archive_read_data((struct archive*)fp, ptr, size); +	/* Report error (negative values) */ +	if(sret < 0) { +		pm_errno = PM_ERR_LIBARCHIVE; +		return(0); +	} else { +		return((size_t)sret); +	} +} + +/* +int _package_changelog_feof(const pmpkg_t *pkg, void *fp) +{ +	// note: this doesn't quite work, no feof in libarchive +	return( archive_read_data((struct archive*)fp, NULL, 0) ); +} +*/ + +/** + * Close a package changelog for reading. Similar to fclose in functionality, + * except that the 'file stream' is from an archive. + * @param pkg the package (file) that the changelog was read from + * @param fp a 'file stream' to the package changelog + * @return whether closing the package changelog stream was successful + */ +int _package_changelog_close(const pmpkg_t *pkg, void *fp) +{ +	return( archive_read_finish((struct archive *)fp) ); +} + + +/** Package file operations struct accessor. We implement this as a method + * rather than a static struct as in be_files because we want to reuse the + * majority of the default_pkg_ops struct and add only a few operations of + * our own on top. The static file_pkg_ops variable inside this function + * lets us only initialize an operations struct once which can always be + * accessed by this method. + */ +static struct pkg_operations *get_file_pkg_ops() +{ +	static struct pkg_operations *file_pkg_ops = NULL; +	/* determine whether our static file_pkg_ops struct has been initialized */ +	if(!file_pkg_ops) { +		MALLOC(file_pkg_ops, sizeof(struct pkg_operations), +				RET_ERR(PM_ERR_MEMORY, NULL)); +		memcpy(file_pkg_ops, &default_pkg_ops, sizeof(struct pkg_operations)); +		file_pkg_ops->changelog_open  = _package_changelog_open; +		file_pkg_ops->changelog_read  = _package_changelog_read; +		file_pkg_ops->changelog_close = _package_changelog_close; +	} +	return(file_pkg_ops); +} + +/**   * Parses the package description file for a package into a pmpkg_t struct.   * @param archive the archive to read from, pointed at the .PKGINFO entry   * @param newpkg an empty pmpkg_t struct to fill with package info @@ -69,21 +177,27 @@ static int parse_descfile(struct archive *a, pmpkg_t *newpkg)  		} else {  			key = _alpm_strtrim(key);  			ptr = _alpm_strtrim(ptr); -			if(!strcmp(key, "pkgname")) { +			if(strcmp(key, "pkgname") == 0) {  				STRDUP(newpkg->name, ptr, RET_ERR(PM_ERR_MEMORY, -1)); -			} else if(!strcmp(key, "pkgver")) { +				newpkg->name_hash = _alpm_hash_sdbm(newpkg->name); +			} else if(strcmp(key, "pkgver") == 0) {  				STRDUP(newpkg->version, ptr, RET_ERR(PM_ERR_MEMORY, -1)); -			} else if(!strcmp(key, "pkgdesc")) { +			} else if(strcmp(key, "pkgdesc") == 0) {  				STRDUP(newpkg->desc, ptr, RET_ERR(PM_ERR_MEMORY, -1)); -			} else if(!strcmp(key, "force")) { -				newpkg->force = 1; -			} else if(!strcmp(key, "group")) { +			} else if(strcmp(key, "force") == 0) { +				/* For backward compatibility, like in sync_db_read */ +				if(!newpkg->epoch) { +					newpkg->epoch = 1; +				} +			} else if(strcmp(key, "epoch") == 0) { +				newpkg->epoch = atoi(ptr); +			} else if(strcmp(key, "group") == 0) {  				newpkg->groups = alpm_list_add(newpkg->groups, strdup(ptr)); -			} else if(!strcmp(key, "url")) { +			} else if(strcmp(key, "url") == 0) {  				STRDUP(newpkg->url, ptr, RET_ERR(PM_ERR_MEMORY, -1)); -			} else if(!strcmp(key, "license")) { +			} else if(strcmp(key, "license") == 0) {  				newpkg->licenses = alpm_list_add(newpkg->licenses, strdup(ptr)); -			} else if(!strcmp(key, "builddate")) { +			} else if(strcmp(key, "builddate") == 0) {  				char first = tolower((unsigned char)ptr[0]);  				if(first > 'a' && first < 'z') {  					struct tm tmp_tm = {0}; /* initialize to null in case of failure */ @@ -94,27 +208,27 @@ static int parse_descfile(struct archive *a, pmpkg_t *newpkg)  				} else {  					newpkg->builddate = atol(ptr);  				} -			} else if(!strcmp(key, "packager")) { +			} else if(strcmp(key, "packager") == 0) {  				STRDUP(newpkg->packager, ptr, RET_ERR(PM_ERR_MEMORY, -1)); -			} else if(!strcmp(key, "arch")) { +			} else if(strcmp(key, "arch") == 0) {  				STRDUP(newpkg->arch, ptr, RET_ERR(PM_ERR_MEMORY, -1)); -			} else if(!strcmp(key, "size")) { +			} else if(strcmp(key, "size") == 0) {  				/* size in the raw package is uncompressed (installed) size */  				newpkg->isize = atol(ptr); -			} else if(!strcmp(key, "depend")) { +			} else if(strcmp(key, "depend") == 0) {  				pmdepend_t *dep = _alpm_splitdep(ptr);  				newpkg->depends = alpm_list_add(newpkg->depends, dep); -			} else if(!strcmp(key, "optdepend")) { +			} else if(strcmp(key, "optdepend") == 0) {  				newpkg->optdepends = alpm_list_add(newpkg->optdepends, strdup(ptr)); -			} else if(!strcmp(key, "conflict")) { +			} else if(strcmp(key, "conflict") == 0) {  				newpkg->conflicts = alpm_list_add(newpkg->conflicts, strdup(ptr)); -			} else if(!strcmp(key, "replaces")) { +			} else if(strcmp(key, "replaces") == 0) {  				newpkg->replaces = alpm_list_add(newpkg->replaces, strdup(ptr)); -			} else if(!strcmp(key, "provides")) { +			} else if(strcmp(key, "provides") == 0) {  				newpkg->provides = alpm_list_add(newpkg->provides, strdup(ptr)); -			} else if(!strcmp(key, "backup")) { +			} else if(strcmp(key, "backup") == 0) {  				newpkg->backup = alpm_list_add(newpkg->backup, strdup(ptr)); -			} else if(!strcmp(key, "makepkgopt")) { +			} else if(strcmp(key, "makepkgopt") == 0) {  				/* not used atm */  			} else {  				_alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n", @@ -232,11 +346,13 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)  		goto pkg_invalid;  	} -  archive_read_finish(archive); +	archive_read_finish(archive);  	/* internal fields for package struct */  	newpkg->origin = PKG_FROM_FILE; +	/* TODO eventually kill/move this? */  	newpkg->origin_data.file = strdup(pkgfile); +	newpkg->ops = get_file_pkg_ops();  	if(full) {  		/* "checking for conflicts" requires a sorted list, ensure that here */ @@ -247,7 +363,7 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)  	} else {  		/* get rid of any partial filelist we may have collected, it is invalid */  		FREELIST(newpkg->files); -		newpkg->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS; +		newpkg->infolevel = INFRQ_BASE | INFRQ_DESC;  	}  	return(newpkg); diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c new file mode 100644 index 00000000..72caa507 --- /dev/null +++ b/lib/libalpm/be_sync.c @@ -0,0 +1,459 @@ +/* + *  be_sync.c + * + *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <errno.h> +#include <ctype.h> +#include <locale.h> + +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> + +/* libalpm */ +#include "util.h" +#include "log.h" +#include "alpm.h" +#include "alpm_list.h" +#include "package.h" +#include "handle.h" +#include "delta.h" +#include "deps.h" +#include "dload.h" + +/** Update a package database + * + * An update of the package database \a db will be attempted. Unless + * \a force is true, the update will only be performed if the remote + * database was modified since the last update. + * + * A transaction is necessary for this operation, in order to obtain a + * database lock. During this transaction the front-end will be informed + * of the download progress of the database via the download callback. + * + * Example: + * @code + * pmdb_t *db; + * int result; + * db = alpm_list_getdata(alpm_option_get_syncdbs()); + * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) { + *     result = alpm_db_update(0, db); + *     alpm_trans_release(); + * + *     if(result > 0) { + *	       printf("Unable to update database: %s\n", alpm_strerrorlast()); + *     } else if(result < 0) { + *         printf("Database already up to date\n"); + *     } else { + *         printf("Database updated\n"); + *     } + * } + * @endcode + * + * @ingroup alpm_databases + * @note After a successful update, the \link alpm_db_get_pkgcache() + * package cache \endlink will be invalidated + * @param force if true, then forces the update, otherwise update only in case + * the database isn't up to date + * @param db pointer to the package database to update + * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up + * to date + */ +int SYMEXPORT alpm_db_update(int force, pmdb_t *db) +{ +	char *dbfile, *syncpath; +	const char *dbpath; +	struct stat buf; +	size_t len; +	int ret; + +	ALPM_LOG_FUNC; + +	/* Sanity checks */ +	ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); +	ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -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(); +	len = strlen(dbpath) + 6; +	MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1)); +	sprintf(syncpath, "%s%s", dbpath, "sync/"); + +	if(stat(syncpath, &buf) != 0) { +		_alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n", +				syncpath); +		if(_alpm_makepath(syncpath) != 0) { +			free(dbfile); +			free(syncpath); +			RET_ERR(PM_ERR_SYSTEM, -1); +		} +	} else if(!S_ISDIR(buf.st_mode)) { +		_alpm_log(PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath); +		if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) { +			free(dbfile); +			free(syncpath); +			RET_ERR(PM_ERR_SYSTEM, -1); +		} +	} + +	ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force); +	free(dbfile); +	free(syncpath); + +	if(ret == 1) { +		/* files match, do nothing */ +		pm_errno = 0; +		return(1); +	} else if(ret == -1) { +		/* pm_errno was set by the download code */ +		_alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast()); +		return(-1); +	} + +	/* Cache needs to be rebuilt */ +	_alpm_db_free_pkgcache(db); + +	return(0); +} + +/* Forward decl so I don't reorganize the whole file right now */ +static int sync_db_read(pmdb_t *db, struct archive *archive, struct archive_entry *entry); + +static int sync_db_populate(pmdb_t *db) +{ +	int count = 0; +	struct archive *archive; +	struct archive_entry *entry; + +	ALPM_LOG_FUNC; + +	ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); + +	if((archive = archive_read_new()) == NULL) +		RET_ERR(PM_ERR_LIBARCHIVE, 1); + +	archive_read_support_compression_all(archive); +	archive_read_support_format_all(archive); + +	if(archive_read_open_filename(archive, _alpm_db_path(db), +				ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { +		_alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), _alpm_db_path(db), +				archive_error_string(archive)); +		RET_ERR(PM_ERR_PKG_OPEN, 1); +	} + +	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { +		const struct stat *st; +		const char *name; +		pmpkg_t *pkg; + +		st = archive_entry_stat(entry); + +		if(S_ISDIR(st->st_mode)) { +			pkg = _alpm_pkg_new(); +			if(pkg == NULL) { +				archive_read_finish(archive); +				return(-1); +			} + +			name = archive_entry_pathname(entry); + +			if(_alpm_splitname(name, pkg) != 0) { +				_alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"), +						name); +				_alpm_pkg_free(pkg); +				continue; +			} + +			/* duplicated database entries are not allowed */ +			if(_alpm_pkg_find(db->pkgcache, pkg->name)) { +				_alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name); +				_alpm_pkg_free(pkg); +				continue; +			} + +			pkg->origin = PKG_FROM_SYNCDB; +			pkg->ops = &default_pkg_ops; +			pkg->origin_data.db = db; + +			/* add to the collection */ +			_alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", +					pkg->name, db->treename); +			db->pkgcache = alpm_list_add(db->pkgcache, pkg); +			count++; +		} else { +			/* we have desc, depends or deltas - parse it */ +			sync_db_read(db, archive, entry); +		} +	} + +	db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp); +	archive_read_finish(archive); + +	return(count); +} + +static int sync_db_read(pmdb_t *db, struct archive *archive, struct archive_entry *entry) +{ +	char line[1024]; +	const char *entryname = NULL; +	char *filename, *pkgname, *p, *q; +	pmpkg_t *pkg; + +	ALPM_LOG_FUNC; + +	if(db == NULL) { +		RET_ERR(PM_ERR_DB_NULL, -1); +	} + +	if(entry != NULL) { +		entryname = archive_entry_pathname(entry); +	} +	if(entryname == NULL) { +		_alpm_log(PM_LOG_DEBUG, "invalid archive entry provided to _alpm_sync_db_read, skipping\n"); +		return(-1); +	} + +	_alpm_log(PM_LOG_FUNCTION, "loading package data from archive entry %s\n", +			entryname); + +	/* get package and db file names */ +	STRDUP(pkgname, entryname, RET_ERR(PM_ERR_MEMORY, -1)); +	p = pkgname + strlen(pkgname); +	for(q = --p; *q && *q != '/'; q--); +	STRDUP(filename, q+1, RET_ERR(PM_ERR_MEMORY, -1)); +	for(p = --q; *p && *p != '-'; p--); +	for(q = --p; *q && *q != '-'; q--); +	*q = '\0'; + +	/* package is already in db due to parsing of directory name */ +	pkg = _alpm_pkg_find(db->pkgcache, pkgname); +	if(pkg == NULL) { +		_alpm_log(PM_LOG_DEBUG, "package %s not found in %s sync database", +					pkgname, db->treename); +		return(-1); +	} + +	if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0 +			|| strcmp(filename, "deltas") == 0) { +		while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) { +			_alpm_strtrim(line); +			if(strcmp(line, "%NAME%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				if(strcmp(_alpm_strtrim(line), pkg->name) != 0) { +					_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name " +								"mismatch on package %s\n"), db->treename, pkg->name); +				} +			} else if(strcmp(line, "%VERSION%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				if(strcmp(_alpm_strtrim(line), pkg->version) != 0) { +					_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version " +								"mismatch on package %s\n"), db->treename, pkg->name); +				} +			} else if(strcmp(line, "%FILENAME%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				STRDUP(pkg->filename, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%DESC%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				STRDUP(pkg->desc, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%GROUPS%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					pkg->groups = alpm_list_add(pkg->groups, linedup); +				} +			} else if(strcmp(line, "%URL%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				STRDUP(pkg->url, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%LICENSE%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && +							strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					pkg->licenses = alpm_list_add(pkg->licenses, linedup); +				} +			} else if(strcmp(line, "%ARCH%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				STRDUP(pkg->arch, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%BUILDDATE%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				_alpm_strtrim(line); + +				char first = tolower((unsigned char)line[0]); +				if(first > 'a' && first < 'z') { +					struct tm tmp_tm = {0}; /* initialize to null in case of failure */ +					setlocale(LC_TIME, "C"); +					strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); +					pkg->builddate = mktime(&tmp_tm); +					setlocale(LC_TIME, ""); +				} else { +					pkg->builddate = atol(line); +				} +			} else if(strcmp(line, "%PACKAGER%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				STRDUP(pkg->packager, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%CSIZE%") == 0) { +				/* NOTE: the CSIZE and SIZE fields both share the "size" field +				 *       in the pkginfo_t struct.  This can be done b/c CSIZE +				 *       is currently only used in sync databases, and SIZE is +				 *       only used in local databases. +				 */ +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				pkg->size = atol(_alpm_strtrim(line)); +				/* also store this value to isize if isize is unset */ +				if(pkg->isize == 0) { +					pkg->isize = pkg->size; +				} +			} else if(strcmp(line, "%ISIZE%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				pkg->isize = atol(_alpm_strtrim(line)); +			} else if(strcmp(line, "%MD5SUM%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				STRDUP(pkg->md5sum, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%REPLACES%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && +							strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					pkg->replaces = alpm_list_add(pkg->replaces, linedup); +				} +			} else if(strcmp(line, "%EPOCH%") == 0) { +				if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { +					goto error; +				} +				pkg->epoch = atoi(_alpm_strtrim(line)); +			} else if(strcmp(line, "%FORCE%") == 0) { +				/* For backward compatibility, treat force as a non-zero epoch +				 * but only if we didn't already have a known epoch value. */ +				if(!pkg->epoch) { +					pkg->epoch = 1; +				} +			} else if(strcmp(line, "%DEPENDS%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && +							strlen(_alpm_strtrim(line))) { +					pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line)); +					pkg->depends = alpm_list_add(pkg->depends, dep); +				} +			} else if(strcmp(line, "%OPTDEPENDS%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && +							strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					pkg->optdepends = alpm_list_add(pkg->optdepends, linedup); +				} +			} else if(strcmp(line, "%CONFLICTS%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && +							strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					pkg->conflicts = alpm_list_add(pkg->conflicts, linedup); +				} +			} else if(strcmp(line, "%PROVIDES%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && +							strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					pkg->provides = alpm_list_add(pkg->provides, linedup); +				} +			} else if(strcmp(line, "%DELTAS%") == 0) { +				while(_alpm_archive_fgets(line, sizeof(line), archive) && strlen(_alpm_strtrim(line))) { +					pmdelta_t *delta = _alpm_delta_parse(line); +					if(delta) { +						pkg->deltas = alpm_list_add(pkg->deltas, delta); +					} +				} +			} +		} +	} else { +		 /* unknown database file */ +		_alpm_log(PM_LOG_DEBUG, "unknown database file: %s", filename); +	} + +error: +	FREE(pkgname); +	FREE(filename); +	/* TODO: return 0 always? */ +	return(0); +} + +struct db_operations sync_db_ops = { +	.populate         = sync_db_populate, +	.unregister       = _alpm_db_unregister, +}; + +pmdb_t *_alpm_db_register_sync(const char *treename) +{ +	pmdb_t *db; +	alpm_list_t *i; + +	ALPM_LOG_FUNC; + +	for(i = handle->dbs_sync; i; i = i->next) { +		pmdb_t *sdb = i->data; +		if(strcmp(treename, sdb->treename) == 0) { +			_alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename); +			return sdb; +		} +	} + +	_alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename); + +	db = _alpm_db_new(treename, 0); +	db->ops = &sync_db_ops; +	if(db == NULL) { +		RET_ERR(PM_ERR_DB_CREATE, NULL); +	} + +	handle->dbs_sync = alpm_list_add(handle->dbs_sync, db); +	return(db); +} + + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/cache.c b/lib/libalpm/cache.c deleted file mode 100644 index a9a7edd9..00000000 --- a/lib/libalpm/cache.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - *  cache.c - * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> - *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License as published by - *  the Free Software Foundation; either version 2 of the License, or - *  (at your option) any later version. - * - *  This program is distributed in the hope that it will be useful, - *  but WITHOUT ANY WARRANTY; without even the implied warranty of - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - *  GNU General Public License for more details. - * - *  You should have received a copy of the GNU General Public License - *  along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> - -/* libalpm */ -#include "cache.h" -#include "alpm_list.h" -#include "log.h" -#include "alpm.h" -#include "util.h" -#include "package.h" -#include "group.h" -#include "db.h" - -/* Returns a new package cache from db. - * It frees the cache if it already exists. - */ -int _alpm_db_load_pkgcache(pmdb_t *db) -{ -	ALPM_LOG_FUNC; - -	if(db == NULL) { -		return(-1); -	} -	_alpm_db_free_pkgcache(db); - -	_alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n", -			db->treename); -	if(_alpm_db_populate(db) == -1) { -		_alpm_log(PM_LOG_DEBUG, -				"failed to load package cache for repository '%s'\n", db->treename); -		return(-1); -	} - -	db->pkgcache_loaded = 1; -	return(0); -} - -void _alpm_db_free_pkgcache(pmdb_t *db) -{ -	ALPM_LOG_FUNC; - -	if(db == NULL || !db->pkgcache_loaded) { -		return; -	} - -	_alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n", -	                        db->treename); - -	alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free); -	alpm_list_free(db->pkgcache); -	db->pkgcache = NULL; -	db->pkgcache_loaded = 0; - -	_alpm_db_free_grpcache(db); -} - -alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db) -{ -	ALPM_LOG_FUNC; - -	if(db == NULL) { -		return(NULL); -	} - -	if(!db->pkgcache_loaded) { -		_alpm_db_load_pkgcache(db); -	} - -	/* hmmm, still NULL ?*/ -	if(!db->pkgcache) { -		_alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename); -	} - -	return(db->pkgcache); -} - -/* "duplicate" pkg with BASE info (to spare some memory) then add it to pkgcache */ -int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg) -{ -	pmpkg_t *newpkg; - -	ALPM_LOG_FUNC; - -	if(db == NULL || !db->pkgcache_loaded || pkg == NULL) { -		return(-1); -	} - -	newpkg = _alpm_pkg_new(); -	if(newpkg == NULL) { -		return(-1); -	} -	newpkg->name = strdup(pkg->name); -	newpkg->version = strdup(pkg->version); -	if(newpkg->name == NULL || newpkg->version == NULL) { -		pm_errno = PM_ERR_MEMORY; -		_alpm_pkg_free(newpkg); -		return(-1); -	} -	newpkg->origin = PKG_FROM_CACHE; -	newpkg->origin_data.db = db; -	newpkg->infolevel = INFRQ_BASE;  - -	_alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n", -						alpm_pkg_get_name(newpkg), db->treename); -	db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp); - -	_alpm_db_free_grpcache(db); - -	return(0); -} - -int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg) -{ -	void *vdata; -	pmpkg_t *data; - -	ALPM_LOG_FUNC; - -	if(db == NULL || !db->pkgcache_loaded || pkg == NULL) { -		return(-1); -	} - -	_alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n", -						alpm_pkg_get_name(pkg), db->treename); - -	db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata); -	data = vdata; -	if(data == NULL) { -		/* package not found */ -		_alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n", -							alpm_pkg_get_name(pkg), db->treename); -		return(-1); -	} - -	_alpm_pkg_free(data); - -	_alpm_db_free_grpcache(db); - -	return(0); -} - -pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target) -{ -	ALPM_LOG_FUNC; - -	if(db == NULL) { -		return(NULL); -	} - -	alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db); -	if(!pkgcache) { -		_alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n", -				target); -		return(NULL); -	} - -	return(_alpm_pkg_find(pkgcache, target)); -} - -/* Returns a new group cache from db. - */ -int _alpm_db_load_grpcache(pmdb_t *db) -{ -	alpm_list_t *lp; - -	ALPM_LOG_FUNC; - -	if(db == NULL) { -		return(-1); -	} - -	_alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n", -			db->treename); - -	for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) { -		const alpm_list_t *i; -		pmpkg_t *pkg = lp->data; - -		for(i = alpm_pkg_get_groups(pkg); i; i = i->next) { -			const char *grpname = i->data; -			alpm_list_t *j; -			pmgrp_t *grp = NULL; -			int found = 0; - -			/* first look through the group cache for a group with this name */ -			for(j = db->grpcache; j; j = j->next) { -				grp = j->data; - -				if(strcmp(grp->name, grpname) == 0 -						&& !alpm_list_find_ptr(grp->packages, pkg)) { -					grp->packages = alpm_list_add(grp->packages, pkg); -					found = 1; -					break; -				} -			} -			if(found) { -				continue; -			} -			/* we didn't find the group, so create a new one with this name */ -			grp = _alpm_grp_new(grpname); -			grp->packages = alpm_list_add(grp->packages, pkg); -			db->grpcache = alpm_list_add(db->grpcache, grp); -		} -	} - -	db->grpcache_loaded = 1; -	return(0); -} - -void _alpm_db_free_grpcache(pmdb_t *db) -{ -	alpm_list_t *lg; - -	ALPM_LOG_FUNC; - -	if(db == NULL || !db->grpcache_loaded) { -		return; -	} - -	_alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n", -	                        db->treename); - -	for(lg = db->grpcache; lg; lg = lg->next) { -		_alpm_grp_free(lg->data); -		lg->data = NULL; -	} -	FREELIST(db->grpcache); -	db->grpcache_loaded = 0; -} - -alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db) -{ -	ALPM_LOG_FUNC; - -	if(db == NULL) { -		return(NULL); -	} - -	if(!db->grpcache_loaded) { -		_alpm_db_load_grpcache(db); -	} - -	return(db->grpcache); -} - -pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target) -{ -	alpm_list_t *i; - -	ALPM_LOG_FUNC; - -	if(db == NULL || target == NULL || strlen(target) == 0) { -		return(NULL); -	} - -	for(i = _alpm_db_get_grpcache(db); i; i = i->next) { -		pmgrp_t *info = i->data; - -		if(strcmp(info->name, target) == 0) { -			return(info); -		} -	} - -	return(NULL); -} - -/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/cache.h b/lib/libalpm/cache.h deleted file mode 100644 index 6ddcd186..00000000 --- a/lib/libalpm/cache.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - *  cache.h - * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> - *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License as published by - *  the Free Software Foundation; either version 2 of the License, or - *  (at your option) any later version. - * - *  This program is distributed in the hope that it will be useful, - *  but WITHOUT ANY WARRANTY; without even the implied warranty of - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - *  GNU General Public License for more details. - * - *  You should have received a copy of the GNU General Public License - *  along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef _ALPM_CACHE_H -#define _ALPM_CACHE_H - -#include "db.h" -#include "alpm_list.h" -#include "group.h" -#include "package.h" - -/* packages */ -int _alpm_db_load_pkgcache(pmdb_t *db); -void _alpm_db_free_pkgcache(pmdb_t *db); -int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg); -int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg); -alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db); -int _alpm_db_ensure_pkgcache(pmdb_t *db, pmdbinfrq_t infolevel); -pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target); -/* groups */ -int _alpm_db_load_grpcache(pmdb_t *db); -void _alpm_db_free_grpcache(pmdb_t *db); -alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db); -pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target); - -#endif /* _ALPM_CACHE_H */ - -/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index e36844a8..2b0efa5a 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -38,7 +38,6 @@  #include "trans.h"  #include "util.h"  #include "log.h" -#include "cache.h"  #include "deps.h"  pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2, const char *reason) @@ -88,8 +87,8 @@ int _alpm_conflict_isin(pmconflict_t *needle, alpm_list_t *haystack)  		char *cpkg2 = conflict->package2;  		char *npkg1 = needle->package1;  		char *npkg2 = needle->package2; -		if((!strcmp(cpkg1, npkg1)  && !strcmp(cpkg2, npkg2)) -				|| (!strcmp(cpkg1, npkg2) && !strcmp(cpkg2, npkg1))) { +		if((strcmp(cpkg1, npkg1) == 0  && strcmp(cpkg2, npkg2) == 0) +				|| (strcmp(cpkg1, npkg2) == 0 && strcmp(cpkg2, npkg1) == 0)) {  			return(1);  		}  	} @@ -110,7 +109,7 @@ static int does_conflict(pmpkg_t *pkg1, const char *conflict, pmpkg_t *pkg2)  	pmdepend_t *conf = _alpm_splitdep(conflict);  	int match = 0; -	match = alpm_depcmp(pkg2, conf); +	match = _alpm_depcmp(pkg2, conf);  	if(match) {  		_alpm_log(PM_LOG_DEBUG, "package %s conflicts with %s (by %s)\n",  				pkg1name, pkg2name, conflict); @@ -321,7 +320,7 @@ static alpm_list_t *chk_filedifference(alpm_list_t *filesA, alpm_list_t *filesB)   */  static alpm_list_t *add_fileconflict(alpm_list_t *conflicts,                      pmfileconflicttype_t type, const char *filestr, -										const char* name1, const char* name2) +                    const char* name1, const char* name2)  {  	pmfileconflict_t *conflict;  	MALLOC(conflict, sizeof(pmfileconflict_t), RET_ERR(PM_ERR_MEMORY, NULL)); diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index c8a91a2b..137f8d04 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -29,7 +29,6 @@  #include <errno.h>  #include <string.h>  #include <sys/stat.h> -#include <dirent.h>  #include <regex.h>  #include <time.h> @@ -39,8 +38,9 @@  #include "log.h"  #include "util.h"  #include "handle.h" -#include "cache.h"  #include "alpm.h" +#include "package.h" +#include "group.h"  /** \addtogroup alpm_databases Database Functions   * @brief Functions to query and manipulate the database of libalpm @@ -80,7 +80,7 @@ pmdb_t SYMEXPORT *alpm_db_register_local(void)  }  /* Helper function for alpm_db_unregister{_all} */ -static void _alpm_db_unregister(pmdb_t *db) +void _alpm_db_unregister(pmdb_t *db)  {  	if(db == NULL) {  		return; @@ -96,6 +96,7 @@ static void _alpm_db_unregister(pmdb_t *db)  int SYMEXPORT alpm_db_unregister_all(void)  {  	alpm_list_t *i; +	pmdb_t *db;  	ALPM_LOG_FUNC; @@ -105,13 +106,16 @@ int SYMEXPORT alpm_db_unregister_all(void)  	ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));  	/* close local database */ -	_alpm_db_unregister(handle->db_local); -	handle->db_local = NULL; +	db = handle->db_local; +	if(db) { +		db->ops->unregister(db); +		handle->db_local = NULL; +	}  	/* and also sync ones */  	for(i = handle->dbs_sync; i; i = i->next) { -		pmdb_t *db = i->data; -		_alpm_db_unregister(db); +		db = i->data; +		db->ops->unregister(db);  		i->data = NULL;  	}  	FREELIST(handle->dbs_sync); @@ -154,7 +158,7 @@ int SYMEXPORT alpm_db_unregister(pmdb_t *db)  		RET_ERR(PM_ERR_DB_NOT_FOUND, -1);  	} -	_alpm_db_unregister(db); +	db->ops->unregister(db);  	return(0);  } @@ -321,7 +325,7 @@ alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, const alpm_list_t* needles)  	return(_alpm_db_search(db, needles));  } -/* Set install reason for a package in db +/** Set install reason for a package in db   * @param db pointer to the package database   * @param name the name of the package   * @param reason the new install reason @@ -341,18 +345,14 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t  	}  	_alpm_log(PM_LOG_DEBUG, "setting install reason %u for %s/%s\n", reason, db->treename, name); -	/* read DESC */ -	if(_alpm_db_read(db, pkg, INFRQ_DESC)) { -		return(-1); -	} -	if(pkg->reason == reason) { +	if(alpm_pkg_get_reason(pkg) == reason) {  		/* we are done */  		return(0);  	}  	/* set reason (in pkgcache) */  	pkg->reason = reason;  	/* write DESC */ -	if(_alpm_db_write(db, pkg, INFRQ_DESC)) { +	if(_alpm_local_db_write(db, pkg, INFRQ_DESC)) {  		return(-1);  	} @@ -361,7 +361,7 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t  /** @} */ -static pmdb_t *_alpm_db_new(const char *treename, int is_local) +pmdb_t *_alpm_db_new(const char *treename, int is_local)  {  	pmdb_t *db; @@ -409,10 +409,10 @@ const char *_alpm_db_path(pmdb_t *db)  			CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));  			sprintf(db->_path, "%s%s/", dbpath, db->treename);  		} else { -			pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 2; +			pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 4;  			CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));  			/* all sync DBs now reside in the sync/ subdir of the dbpath */ -			sprintf(db->_path, "%ssync/%s/", dbpath, db->treename); +			sprintf(db->_path, "%ssync/%s.db", dbpath, db->treename);  		}  		_alpm_log(PM_LOG_DEBUG, "database path for tree %s set to %s\n",  				db->treename, db->_path); @@ -503,52 +503,246 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)  	return(ret);  } -pmdb_t *_alpm_db_register_local(void) +/* Returns a new package cache from db. + * It frees the cache if it already exists. + */ +int _alpm_db_load_pkgcache(pmdb_t *db)  { -	pmdb_t *db; +	ALPM_LOG_FUNC; + +	if(db == NULL) { +		return(-1); +	} +	_alpm_db_free_pkgcache(db); + +	_alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n", +			db->treename); +	if(db->ops->populate(db) == -1) { +		_alpm_log(PM_LOG_DEBUG, +				"failed to load package cache for repository '%s'\n", db->treename); +		return(-1); +	} +	db->pkgcache_loaded = 1; +	return(0); +} + +void _alpm_db_free_pkgcache(pmdb_t *db) +{  	ALPM_LOG_FUNC; -	if(handle->db_local != NULL) { -		_alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n")); -		RET_ERR(PM_ERR_DB_NOT_NULL, NULL); +	if(db == NULL || !db->pkgcache_loaded) { +		return;  	} -	_alpm_log(PM_LOG_DEBUG, "registering local database\n"); +	_alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n", +	                        db->treename); + +	alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free); +	alpm_list_free(db->pkgcache); +	db->pkgcache_loaded = 0; + +	_alpm_db_free_grpcache(db); +} + +alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db) +{ +	ALPM_LOG_FUNC; -	db = _alpm_db_new("local", 1);  	if(db == NULL) { -		RET_ERR(PM_ERR_DB_CREATE, NULL); +		return(NULL);  	} -	handle->db_local = db; -	return(db); +	if(!db->pkgcache_loaded) { +		_alpm_db_load_pkgcache(db); +	} + +	/* hmmm, still NULL ?*/ +	if(!db->pkgcache) { +		_alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename); +	} + +	return(db->pkgcache);  } -pmdb_t *_alpm_db_register_sync(const char *treename) +/* "duplicate" pkg then add it to pkgcache */ +int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)  { -	pmdb_t *db; -	alpm_list_t *i; +	pmpkg_t *newpkg;  	ALPM_LOG_FUNC; -	for(i = handle->dbs_sync; i; i = i->next) { -		pmdb_t *sdb = i->data; -		if(strcmp(treename, sdb->treename) == 0) { -			_alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename); -			return sdb; +	if(db == NULL || !db->pkgcache_loaded || pkg == NULL) { +		return(-1); +	} + +	newpkg = _alpm_pkg_dup(pkg); +	if(newpkg == NULL) { +		return(-1); +	} + +	_alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n", +						alpm_pkg_get_name(newpkg), db->treename); +	db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp); + +	_alpm_db_free_grpcache(db); + +	return(0); +} + +int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg) +{ +	void *vdata; +	pmpkg_t *data; + +	ALPM_LOG_FUNC; + +	if(db == NULL || !db->pkgcache_loaded || pkg == NULL) { +		return(-1); +	} + +	_alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n", +						alpm_pkg_get_name(pkg), db->treename); + +	db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata); +	data = vdata; +	if(data == NULL) { +		/* package not found */ +		_alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n", +							alpm_pkg_get_name(pkg), db->treename); +		return(-1); +	} + +	_alpm_pkg_free(data); + +	_alpm_db_free_grpcache(db); + +	return(0); +} + +pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target) +{ +	ALPM_LOG_FUNC; + +	if(db == NULL) { +		return(NULL); +	} + +	alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db); +	if(!pkgcache) { +		_alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n", +				target); +		return(NULL); +	} + +	return(_alpm_pkg_find(pkgcache, target)); +} + +/* Returns a new group cache from db. + */ +int _alpm_db_load_grpcache(pmdb_t *db) +{ +	alpm_list_t *lp; + +	ALPM_LOG_FUNC; + +	if(db == NULL) { +		return(-1); +	} + +	_alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n", +			db->treename); + +	for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) { +		const alpm_list_t *i; +		pmpkg_t *pkg = lp->data; + +		for(i = alpm_pkg_get_groups(pkg); i; i = i->next) { +			const char *grpname = i->data; +			alpm_list_t *j; +			pmgrp_t *grp = NULL; +			int found = 0; + +			/* first look through the group cache for a group with this name */ +			for(j = db->grpcache; j; j = j->next) { +				grp = j->data; + +				if(strcmp(grp->name, grpname) == 0 +						&& !alpm_list_find_ptr(grp->packages, pkg)) { +					grp->packages = alpm_list_add(grp->packages, pkg); +					found = 1; +					break; +				} +			} +			if(found) { +				continue; +			} +			/* we didn't find the group, so create a new one with this name */ +			grp = _alpm_grp_new(grpname); +			grp->packages = alpm_list_add(grp->packages, pkg); +			db->grpcache = alpm_list_add(db->grpcache, grp);  		}  	} -	_alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename); +	db->grpcache_loaded = 1; +	return(0); +} + +void _alpm_db_free_grpcache(pmdb_t *db) +{ +	alpm_list_t *lg; + +	ALPM_LOG_FUNC; + +	if(db == NULL || !db->grpcache_loaded) { +		return; +	} + +	_alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n", +	                        db->treename); + +	for(lg = db->grpcache; lg; lg = lg->next) { +		_alpm_grp_free(lg->data); +		lg->data = NULL; +	} +	FREELIST(db->grpcache); +	db->grpcache_loaded = 0; +} + +alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db) +{ +	ALPM_LOG_FUNC; -	db = _alpm_db_new(treename, 0);  	if(db == NULL) { -		RET_ERR(PM_ERR_DB_CREATE, NULL); +		return(NULL);  	} -	handle->dbs_sync = alpm_list_add(handle->dbs_sync, db); -	return(db); +	if(!db->grpcache_loaded) { +		_alpm_db_load_grpcache(db); +	} + +	return(db->grpcache); +} + +pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target) +{ +	alpm_list_t *i; + +	ALPM_LOG_FUNC; + +	if(db == NULL || target == NULL || strlen(target) == 0) { +		return(NULL); +	} + +	for(i = _alpm_db_get_grpcache(db); i; i = i->next) { +		pmgrp_t *info = i->data; + +		if(strcmp(info->name, target) == 0) { +			return(info); +		} +	} + +	return(NULL);  }  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 1851b5c9..ace366d1 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -26,19 +26,26 @@  #include <limits.h>  #include <time.h> +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> +  /* Database entries */  typedef enum _pmdbinfrq_t {  	INFRQ_BASE = 1,  	INFRQ_DESC = (1 << 1), -	INFRQ_DEPENDS = (1 << 2), -	INFRQ_FILES = (1 << 3), -	INFRQ_SCRIPTLET = (1 << 4), -	INFRQ_DELTAS = (1 << 5), -	INFRQ_DSIZE = (1 << 6), +	INFRQ_FILES = (1 << 2), +	INFRQ_SCRIPTLET = (1 << 3), +	INFRQ_DSIZE = (1 << 4),  	/* ALL should be info stored in the package or database */ -	INFRQ_ALL = 0x3F +	INFRQ_ALL = 0x1F  } pmdbinfrq_t; +struct db_operations { +	int (*populate) (pmdb_t *); +	void (*unregister) (pmdb_t *); +}; +  /* Database */  struct __pmdb_t {  	char *treename; @@ -46,12 +53,16 @@ struct __pmdb_t {  	char *_path;  	int pkgcache_loaded;  	int grpcache_loaded; +	/* also indicates whether we are RO or RW */  	int is_local;  	alpm_list_t *pkgcache;  	alpm_list_t *grpcache;  	alpm_list_t *servers; + +	struct db_operations *ops;  }; +  /* db.c, database general calls */  void _alpm_db_free(pmdb_t *db);  const char *_alpm_db_path(pmdb_t *db); @@ -59,13 +70,29 @@ int _alpm_db_cmp(const void *d1, const void *d2);  alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);  pmdb_t *_alpm_db_register_local(void);  pmdb_t *_alpm_db_register_sync(const char *treename); +void _alpm_db_unregister(pmdb_t *db); +pmdb_t *_alpm_db_new(const char *treename, int is_local); + +/* be_*.c, backend specific calls */ +int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); +int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info); +int _alpm_local_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); +int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info); -/* be.c, backend specific calls */ -int _alpm_db_populate(pmdb_t *db); -int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); -int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info); -int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); -int _alpm_db_remove(pmdb_t *db, pmpkg_t *info); +/* cache bullshit */ +/* packages */ +int _alpm_db_load_pkgcache(pmdb_t *db); +void _alpm_db_free_pkgcache(pmdb_t *db); +int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg); +int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg); +alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db); +int _alpm_db_ensure_pkgcache(pmdb_t *db, pmdbinfrq_t infolevel); +pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target); +/* groups */ +int _alpm_db_load_grpcache(pmdb_t *db); +void _alpm_db_free_grpcache(pmdb_t *db); +alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db); +pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target);  #endif /* _ALPM_DB_H */ diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h index 76283380..7d8d5b0f 100644 --- a/lib/libalpm/delta.h +++ b/lib/libalpm/delta.h @@ -44,6 +44,9 @@ void _alpm_delta_free(pmdelta_t *delta);  off_t _alpm_shortest_delta_path(alpm_list_t *deltas,  		const char *to, alpm_list_t **path); +/* max percent of package size to download deltas */ +#define MAX_DELTA_RATIO 0.7 +  #endif /* _ALPM_DELTA_H */  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 26f9b16d..21578293 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -34,7 +34,6 @@  #include "graph.h"  #include "package.h"  #include "db.h" -#include "cache.h"  #include "handle.h"  void _alpm_dep_free(pmdepend_t *dep) @@ -196,36 +195,25 @@ pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep)  	for(i = pkgs; i; i = alpm_list_next(i)) {  		pmpkg_t *pkg = i->data; -		if(alpm_depcmp(pkg, dep)) { +		if(_alpm_depcmp(pkg, dep)) {  			return(pkg);  		}  	}  	return(NULL);  } -/** Checks dependencies and returns missing ones in a list. - * Dependencies can include versions with depmod operators. - * @param db pointer to the local package database - * @param targets an alpm_list_t* of dependencies strings to satisfy - * @return an alpm_list_t* of missing dependencies strings +/** Find a package satisfying a specified dependency. + * The dependency can include versions with depmod operators. + * @param pkgs an alpm_list_t* of pmpkg_t where the satisfier will be searched + * @param depstring package or provision name, versioned or not + * @return a pmpkg_t* satisfying depstring   */ -alpm_list_t SYMEXPORT *alpm_deptest(pmdb_t *db, alpm_list_t *targets) +pmpkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring)  { -	alpm_list_t *i, *ret = NULL; - -	for(i = targets; i; i = alpm_list_next(i)) { -		pmdepend_t *dep; -		char *target; - -		target = alpm_list_getdata(i); -		dep = _alpm_splitdep(target); - -		if(!_alpm_find_dep_satisfier(_alpm_db_get_pkgcache(db), dep)) { -			ret = alpm_list_add(ret, target); -		} -		_alpm_dep_free(dep); -	} -	return(ret); +	pmdepend_t *dep = _alpm_splitdep(depstring); +	pmpkg_t *pkg = _alpm_find_dep_satisfier(pkgs, dep); +	_alpm_dep_free(dep); +	return(pkg);  }  /** Checks dependencies and returns missing ones in a list. @@ -248,8 +236,8 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_list_t *pkglist, int reversedeps,  	targets = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade));  	for(i = pkglist; i; i = i->next) { -		void *pkg = i->data; -		if(alpm_list_find(targets, pkg, _alpm_pkg_cmp)) { +		pmpkg_t *pkg = i->data; +		if(_alpm_pkg_find(targets, pkg->name)) {  			modified = alpm_list_add(modified, pkg);  		} else {  			dblist = alpm_list_add(dblist, pkg); @@ -331,7 +319,7 @@ static int dep_vercmp(const char *version1, pmdepmod_t mod,  	return(equal);  } -int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep) +int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)  {  	alpm_list_t *i; @@ -525,7 +513,7 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,  	/* 1. literals */  	for(i = dbs; i; i = i->next) {  		pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name); -		if(pkg && alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) { +		if(pkg && _alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) {  			if(_alpm_pkg_should_ignore(pkg)) {  				int install = 0;  				if (prompt) { @@ -546,7 +534,7 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,  	for(i = dbs; i; i = i->next) {  		for(j = _alpm_db_get_pkgcache(i->data); j; j = j->next) {  			pmpkg_t *pkg = j->data; -			if(alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) && +			if(_alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) != 0 &&  			             !_alpm_pkg_find(excluding, pkg->name)) {  				if(_alpm_pkg_should_ignore(pkg)) {  					int install = 0; @@ -672,7 +660,7 @@ int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2)  {  	alpm_list_t *i;  	for(i = alpm_pkg_get_depends(pkg1); i; i = i->next) { -		if(alpm_depcmp(pkg2, i->data)) { +		if(_alpm_depcmp(pkg2, i->data)) {  			return(1);  		}  	} diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index ffc3aeeb..6fa763e1 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -55,6 +55,7 @@ int _alpm_resolvedeps(alpm_list_t *localpkgs, alpm_list_t *dbs_sync, pmpkg_t *pk  int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2);  pmdepend_t *_alpm_splitdep(const char *depstring);  pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep); +int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep);  #endif /* _ALPM_DEPS_H */ diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c new file mode 100644 index 00000000..97f28ab2 --- /dev/null +++ b/lib/libalpm/diskspace.c @@ -0,0 +1,324 @@ +/* + *  diskspace.c + * + *  Copyright (c) 2010 Pacman Development Team <pacman-dev@archlinux.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#if defined(HAVE_MNTENT_H) +#include <mntent.h> +#endif +#if defined(HAVE_SYS_STATVFS_H) +#include <sys/statvfs.h> +#endif +#if defined(HAVE_SYS_PARAM_H) +#include <sys/param.h> +#endif +#if defined(HAVE_SYS_MOUNT_H) +#include <sys/mount.h> +#endif +#if defined(HAVE_SYS_UCRED_H) +#include <sys/ucred.h> +#endif +#if defined(HAVE_SYS_TYPES_H) +#include <sys/types.h> +#endif + +#include <math.h> + +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> + +/* libalpm */ +#include "diskspace.h" +#include "alpm_list.h" +#include "util.h" +#include "log.h" +#include "trans.h" +#include "handle.h" + +static int mount_point_cmp(const void *p1, const void *p2) +{ +	const alpm_mountpoint_t *mp1 = p1; +	const alpm_mountpoint_t *mp2 = p2; +	return(strcmp(mp1->mount_dir, mp2->mount_dir)); +} + +static alpm_list_t *mount_point_list(void) +{ +	alpm_list_t *mount_points = NULL; +	alpm_mountpoint_t *mp; + +#if defined HAVE_GETMNTENT +	struct mntent *mnt; +	FILE *fp; +	FSSTATSTYPE fsp; + +	fp = setmntent(MOUNTED, "r"); + +	if (fp == NULL) { +		return(NULL); +	} + +	while((mnt = getmntent(fp))) { +		if(statvfs(mnt->mnt_dir, &fsp) != 0) { +			_alpm_log(PM_LOG_WARNING, +					_("could not get filesystem information for %s\n"), mnt->mnt_dir); +			continue; +		} + +		MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL)); +		mp->mount_dir = strdup(mnt->mnt_dir); +		memcpy(&(mp->fsp), &fsp, sizeof(FSSTATSTYPE)); + +		mp->blocks_needed = 0; +		mp->max_blocks_needed = 0; +		mp->used = 0; + +		mount_points = alpm_list_add(mount_points, mp); +	} + +	endmntent(fp); +#elif defined HAVE_GETMNTINFO +	int entries; +	FSSTATSTYPE *fsp; + +	entries = getmntinfo(&fsp, MNT_NOWAIT); + +	if (entries < 0) { +		return NULL; +	} + +	for(; entries-- > 0; fsp++) { +		MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL)); +		mp->mount_dir = strdup(fsp->f_mntonname); +		memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE)); + +		mp->blocks_needed = 0; +		mp->max_blocks_needed = 0; + +		mount_points = alpm_list_add(mount_points, mp); +	} +#endif + +	mount_points = alpm_list_msort(mount_points, alpm_list_count(mount_points), +			mount_point_cmp); +	return(mount_points); +} + +static alpm_list_t *match_mount_point(const alpm_list_t *mount_points, +		const char *file) +{ +	char real_path[PATH_MAX]; +	snprintf(real_path, PATH_MAX, "%s%s", handle->root, file); + +	alpm_list_t *mp = alpm_list_last(mount_points); +	do { +		alpm_mountpoint_t *data = mp->data; + +		if(strncmp(data->mount_dir, real_path, strlen(data->mount_dir)) == 0) { +			return(mp); +		} + +		mp = mp->prev; +	} while (mp != alpm_list_last(mount_points)); + +	/* should not get here... */ +	return(NULL); +} + +static int calculate_removed_size(const alpm_list_t *mount_points, +		pmpkg_t *pkg) +{ +	alpm_list_t *file; + +	alpm_list_t *files = alpm_pkg_get_files(pkg); +	for(file = files; file; file = file->next) { +		alpm_list_t *mp; +		alpm_mountpoint_t *data; +		struct stat st; +		char path[PATH_MAX]; +		const char *filename = file->data; + +		/* skip directories to be consistent with libarchive that reports them +		 * to be zero size and to prevent multiple counting across packages */ +		if(*(filename + strlen(filename) - 1) == '/') { +			continue; +		} + +		mp = match_mount_point(mount_points, filename); +		if(mp == NULL) { +			_alpm_log(PM_LOG_WARNING, +					_("could not determine mount point for file %s"), filename); +			continue; +		} + +		snprintf(path, PATH_MAX, "%s%s", handle->root, filename); +		_alpm_lstat(path, &st); + +		/* skip symlinks to be consistent with libarchive that reports them to +		 * be zero size */ +		if(S_ISLNK(st.st_mode)) { +			continue; +		} + +		data = mp->data; +		data->blocks_needed -= ceil((double)(st.st_size) / +		                            (double)(data->fsp.f_bsize)); +		data->used = 1; +	} + +	return(0); +} + +static int calculate_installed_size(const alpm_list_t *mount_points, +		pmpkg_t *pkg) +{ +	int ret=0; +	struct archive *archive; +	struct archive_entry *entry; +	const char *file; + +	if ((archive = archive_read_new()) == NULL) { +		pm_errno = PM_ERR_LIBARCHIVE; +		ret = -1; +		goto cleanup; +	} + +	archive_read_support_compression_all(archive); +	archive_read_support_format_all(archive); + +	if(archive_read_open_filename(archive, pkg->origin_data.file, +				ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { +		pm_errno = PM_ERR_PKG_OPEN; +		ret = -1; +		goto cleanup; +	} + +	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { +		alpm_list_t *mp; +		alpm_mountpoint_t *data; + +		file = archive_entry_pathname(entry); + +		/* approximate space requirements for db entries */ +		if(file[0] == '.') { +			file = alpm_option_get_dbpath(); +		} + +		mp = match_mount_point(mount_points, file); +		if(mp == NULL) { +			_alpm_log(PM_LOG_WARNING, +					_("could not determine mount point for file %s"), file); +			continue; +		} + +		data = mp->data; +		data->blocks_needed += ceil((double)(archive_entry_size(entry)) / +		                            (double)(data->fsp.f_bsize)); +		data->used = 1; +	} + +	archive_read_finish(archive); + +cleanup: +	return(ret); +} + +int _alpm_check_diskspace(pmtrans_t *trans, pmdb_t *db_local) +{ +	alpm_list_t *mount_points, *i; +	int replaces = 0, abort = 0; +	alpm_list_t *targ; +	pmpkg_t *pkg; +	int numtargs = alpm_list_count(trans->add); +	int current = 0; + +	mount_points = mount_point_list(); +	if(mount_points == NULL) { +		_alpm_log(PM_LOG_ERROR, _("could not determine filesystem mount points")); +		return(-1); +	} + +	replaces = alpm_list_count(trans->remove); +	if(replaces) { +		numtargs += replaces; +		for(targ = trans->remove; targ; targ = targ->next, current++) { +			double percent = (double)current / numtargs; +			PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", (percent * 100), +					numtargs, current); + +			pkg = targ->data; +			calculate_removed_size(mount_points, pkg); +		} +	} + +	for(targ = trans->add; targ; targ = targ->next, current++) { +		double percent = (double)current / numtargs; +		PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", (percent * 100), +				numtargs, current); + +		pkg = targ->data; +		/* is this package already installed? */ +		if(_alpm_db_get_pkgfromcache(db_local, pkg->name)) { +			calculate_removed_size(mount_points, pkg); +		} +		calculate_installed_size(mount_points, pkg); + +		for(i = mount_points; i; i = alpm_list_next(i)) { +			alpm_mountpoint_t *data = i->data; +			if(data->blocks_needed > data->max_blocks_needed) { +				data->max_blocks_needed = data->blocks_needed; +			} +		} +	} + +	PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", 100, +			numtargs, current); + +	for(i = mount_points; i; i = alpm_list_next(i)) { +		alpm_mountpoint_t *data = i->data; +		if(data->used == 1) { +			/* cushion is roughly min(5% capacity, 20MiB) */ +			long fivepc = (data->fsp.f_blocks / 20) + 1; +			long twentymb = (20 * 1024 * 1024 / data->fsp.f_bsize) + 1; +			long cushion = fivepc < twentymb ? fivepc : twentymb; + +			_alpm_log(PM_LOG_DEBUG, "partition %s, needed %ld, cushion %ld, free %ld\n", +					data->mount_dir, data->max_blocks_needed, cushion, +					(unsigned long)data->fsp.f_bfree); +			if(data->max_blocks_needed + cushion > data->fsp.f_bfree) { +				abort = 1; +			} +		} +	} + +	for(i = mount_points; i; i = alpm_list_next(i)) { +		alpm_mountpoint_t *data = i->data; +		FREE(data->mount_dir); +	} +	FREELIST(mount_points); + +	if(abort) { +		RET_ERR(PM_ERR_DISK_SPACE, -1); +	} + +	return(0); +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/diskspace.h b/lib/libalpm/diskspace.h new file mode 100644 index 00000000..e73497ef --- /dev/null +++ b/lib/libalpm/diskspace.h @@ -0,0 +1,46 @@ +/* + *  diskspace.h + * + *  Copyright (c) 2010 Pacman Development Team <pacman-dev@archlinux.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _ALPM_DISKSPACE_H +#define _ALPM_DISKSPACE_H + +#if defined(HAVE_SYS_MOUNT_H) +#include <sys/mount.h> +#endif +#if defined(HAVE_SYS_STATVFS_H) +#include <sys/statvfs.h> +#endif + +#include "alpm.h" + +typedef struct __alpm_mountpoint_t { +	/* mount point information */ +	char *mount_dir; +	/* storage for additional disk usage calculations */ +	long blocks_needed; +	long max_blocks_needed; +	int used; +	FSSTATSTYPE fsp; +} alpm_mountpoint_t; + +int _alpm_check_diskspace(pmtrans_t *trans, pmdb_t *db_local); + +#endif /* _ALPM_DISKSPACE_H */ + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index c11148d1..1cb24e61 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -38,7 +38,7 @@  #include <sys/param.h> /* MAXHOSTNAMELEN */  #endif -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  #include <fetch.h>  #endif @@ -58,7 +58,7 @@ static char *get_filename(const char *url) {  	return(filename);  } -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  static char *get_destfile(const char *path, const char *filename) {  	char *destfile;  	/* len = localpath len + filename len + null */ @@ -89,7 +89,7 @@ static const char *gethost(struct url *fileurl)  }  int dload_interrupted; -static RETSIGTYPE inthandler(int signum) +static void inthandler(int signum)  {  	dload_interrupted = 1;  } @@ -251,7 +251,7 @@ static int download_internal(const char *url, const char *localpath,  		check_stop();  		size_t nwritten = 0;  		nwritten = fwrite(buffer, 1, nread, localf); -		if((nwritten != nread) || ferror(localf)) { +		if((nwritten != (size_t)nread) || ferror(localf)) {  			pm_errno = PM_ERR_RETRIEVE;  			_alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"),  					tempfile, strerror(errno)); @@ -338,7 +338,7 @@ cleanup:  static int download(const char *url, const char *localpath,  		int force) {  	if(handle->fetchcb == NULL) { -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  		return(download_internal(url, localpath, force));  #else  		RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 8d8d0458..78a78667 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -31,7 +31,7 @@  #include <sys/param.h> /* MAXHOSTNAMELEN */  #endif -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  #include <fetch.h> /* fetchLastErrString */  #endif @@ -60,6 +60,8 @@ const char SYMEXPORT *alpm_strerror(int err)  			return _("could not find or read directory");  		case PM_ERR_WRONG_ARGS:  			return _("wrong or NULL argument passed"); +		case PM_ERR_DISK_SPACE: +			return _("not enough disk space");  		/* Interface */  		case PM_ERR_HANDLE_NULL:  			return _("library not initialized"); @@ -145,7 +147,7 @@ const char SYMEXPORT *alpm_strerror(int err)  			 * error string instead. */  			return _("libarchive error");  		case PM_ERR_LIBFETCH: -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  			return fetchLastErrString;  #else  			/* obviously shouldn't get here... */ diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index aa34cf45..ffa5dd67 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -232,6 +232,15 @@ int SYMEXPORT alpm_option_get_usedelta()  	return handle->usedelta;  } +int SYMEXPORT alpm_option_get_checkspace() +{ +	if (handle == NULL) { +		pm_errno = PM_ERR_HANDLE_NULL; +		return -1; +	} +	return handle->checkspace; +} +  pmdb_t SYMEXPORT *alpm_option_get_localdb()  {  	if (handle == NULL) { @@ -550,4 +559,9 @@ void SYMEXPORT alpm_option_set_usedelta(int usedelta)  	handle->usedelta = usedelta;  } +void SYMEXPORT alpm_option_set_checkspace(int checkspace) +{ +	handle->checkspace = checkspace; +} +  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 1834994e..46414b95 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -60,6 +60,7 @@ typedef struct _pmhandle_t {  	int usesyslog;    /* Use syslog instead of logfile? */ /* TODO move to frontend */  	char *arch;       /* Architecture of packages we should allow */  	int usedelta;     /* Download deltas if possible */ +	int checkspace;   /* Check disk space before installing */  } pmhandle_t;  /* global handle variable */ diff --git a/lib/libalpm/md5.c b/lib/libalpm/md5.c index 7d2716f2..90635046 100644 --- a/lib/libalpm/md5.c +++ b/lib/libalpm/md5.c @@ -36,6 +36,8 @@   *        int md5_file( char *path, unsigned char *output )   *      to   *        int md5_file( const char *path, unsigned char *output ) + *  * use a dynamically-allocated buffer in md5_file, and increase the size + *    for performance reasons   *  * various static/inline changes   *   *  NOTE: XySSL has been renamed to PolarSSL, which is available at @@ -44,6 +46,7 @@  #include <string.h>  #include <stdio.h> +#include <stdlib.h>  #include "md5.h" @@ -309,11 +312,16 @@ int md5_file( const char *path, unsigned char output[16] )      FILE *f;      size_t n;      md5_context ctx; -    unsigned char buf[1024]; +    unsigned char *buf; -    if( ( f = fopen( path, "rb" ) ) == NULL ) +    if( ( buf = calloc(8192, sizeof(unsigned char)) ) == NULL )          return( 1 ); +    if( ( f = fopen( path, "rb" ) ) == NULL ) { +        free( buf ); +        return( 1 ); +    } +      md5_starts( &ctx );      while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) @@ -322,6 +330,7 @@ int md5_file( const char *path, unsigned char output[16] )      md5_finish( &ctx, output );      memset( &ctx, 0, sizeof( md5_context ) ); +    free( buf );      if( ferror( f ) != 0 )      { diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index becbc60f..2ea51251 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -32,17 +32,12 @@  #include <sys/types.h>  #include <sys/stat.h> -/* libarchive */ -#include <archive.h> -#include <archive_entry.h> -  /* libalpm */  #include "package.h"  #include "alpm_list.h"  #include "log.h"  #include "util.h"  #include "db.h" -#include "cache.h"  #include "delta.h"  #include "handle.h"  #include "deps.h" @@ -63,7 +58,7 @@ int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)  	ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));  	/* Only free packages loaded in user space */ -	if(pkg->origin != PKG_FROM_CACHE) { +	if(pkg->origin == PKG_FROM_FILE) {  		_alpm_pkg_free(pkg);  	} @@ -83,8 +78,7 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)  	ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));  	/* We only inspect packages from sync repositories */ -	ASSERT(pkg->origin == PKG_FROM_CACHE, RET_ERR(PM_ERR_PKG_INVALID, -1)); -	ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1)); +	ASSERT(pkg->origin == PKG_FROM_SYNCDB, RET_ERR(PM_ERR_PKG_INVALID, -1));  	fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg)); @@ -100,334 +94,196 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)  	return(retval);  } +/* Default package accessor functions. These will get overridden by any + * backend logic that needs lazy access, such as the local database through + * a lazy-load cache. However, the defaults will work just fine for fully- + * populated package structures. */ +const char *_pkg_get_filename(pmpkg_t *pkg)    { return pkg->filename; } +const char *_pkg_get_name(pmpkg_t *pkg)        { return pkg->name; } +const char *_pkg_get_version(pmpkg_t *pkg)     { return pkg->version; } +const char *_pkg_get_desc(pmpkg_t *pkg)        { return pkg->desc; } +const char *_pkg_get_url(pmpkg_t *pkg)         { return pkg->url; } +time_t _pkg_get_builddate(pmpkg_t *pkg)        { return pkg->builddate; } +time_t _pkg_get_installdate(pmpkg_t *pkg)      { return pkg->installdate; } +const char *_pkg_get_packager(pmpkg_t *pkg)    { return pkg->packager; } +const char *_pkg_get_md5sum(pmpkg_t *pkg)      { return pkg->md5sum; } +const char *_pkg_get_arch(pmpkg_t *pkg)        { return pkg->arch; } +off_t _pkg_get_size(pmpkg_t *pkg)              { return pkg->size; } +off_t _pkg_get_isize(pmpkg_t *pkg)             { return pkg->isize; } +pmpkgreason_t _pkg_get_reason(pmpkg_t *pkg)    { return pkg->reason; } +int _pkg_get_epoch(pmpkg_t *pkg)               { return pkg->epoch; } +int _pkg_has_scriptlet(pmpkg_t *pkg)           { return pkg->scriptlet; } + +alpm_list_t *_pkg_get_licenses(pmpkg_t *pkg)   { return pkg->licenses; } +alpm_list_t *_pkg_get_groups(pmpkg_t *pkg)     { return pkg->groups; } +alpm_list_t *_pkg_get_depends(pmpkg_t *pkg)    { return pkg->depends; } +alpm_list_t *_pkg_get_optdepends(pmpkg_t *pkg) { return pkg->optdepends; } +alpm_list_t *_pkg_get_conflicts(pmpkg_t *pkg)  { return pkg->conflicts; } +alpm_list_t *_pkg_get_provides(pmpkg_t *pkg)   { return pkg->provides; } +alpm_list_t *_pkg_get_replaces(pmpkg_t *pkg)   { return pkg->replaces; } +alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg)     { return pkg->deltas; } +alpm_list_t *_pkg_get_files(pmpkg_t *pkg)      { return pkg->files; } +alpm_list_t *_pkg_get_backup(pmpkg_t *pkg)     { return pkg->backup; } + +/** The standard package operations struct. Get fields directly from the + * struct itself with no abstraction layer or any type of lazy loading. + */ +struct pkg_operations default_pkg_ops = { +	.get_filename    = _pkg_get_filename, +	.get_name        = _pkg_get_name, +	.get_version     = _pkg_get_version, +	.get_desc        = _pkg_get_desc, +	.get_url         = _pkg_get_url, +	.get_builddate   = _pkg_get_builddate, +	.get_installdate = _pkg_get_installdate, +	.get_packager    = _pkg_get_packager, +	.get_md5sum      = _pkg_get_md5sum, +	.get_arch        = _pkg_get_arch, +	.get_size        = _pkg_get_size, +	.get_isize       = _pkg_get_isize, +	.get_reason      = _pkg_get_reason, +	.get_epoch       = _pkg_get_epoch, +	.has_scriptlet   = _pkg_has_scriptlet, +	.get_licenses    = _pkg_get_licenses, +	.get_groups      = _pkg_get_groups, +	.get_depends     = _pkg_get_depends, +	.get_optdepends  = _pkg_get_optdepends, +	.get_conflicts   = _pkg_get_conflicts, +	.get_provides    = _pkg_get_provides, +	.get_replaces    = _pkg_get_replaces, +	.get_deltas      = _pkg_get_deltas, +	.get_files       = _pkg_get_files, +	.get_backup      = _pkg_get_backup, +}; + +/* Public functions for getting package information. These functions + * delegate the hard work to the function callbacks attached to each + * package, which depend on where the package was loaded from. */  const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} - -	return pkg->filename; +	return pkg->ops->get_filename(pkg);  }  const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)  { -	ASSERT(pkg != NULL, return(NULL)); -	return pkg->name; +	return pkg->ops->get_name(pkg);  }  const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)  { -	ASSERT(pkg != NULL, return(NULL)); -	return pkg->version; +	return pkg->ops->get_version(pkg);  }  const char SYMEXPORT *alpm_pkg_get_desc(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->desc; +	return pkg->ops->get_desc(pkg);  }  const char SYMEXPORT *alpm_pkg_get_url(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->url; +	return pkg->ops->get_url(pkg);  }  time_t SYMEXPORT alpm_pkg_get_builddate(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(0)); -	ASSERT(pkg != NULL, return(0)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->builddate; +	return pkg->ops->get_builddate(pkg);  }  time_t SYMEXPORT alpm_pkg_get_installdate(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(0)); -	ASSERT(pkg != NULL, return(0)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->installdate; +	return pkg->ops->get_installdate(pkg);  }  const char SYMEXPORT *alpm_pkg_get_packager(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->packager; +	return pkg->ops->get_packager(pkg);  }  const char SYMEXPORT *alpm_pkg_get_md5sum(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->md5sum; +	return pkg->ops->get_md5sum(pkg);  }  const char SYMEXPORT *alpm_pkg_get_arch(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->arch; +	return pkg->ops->get_arch(pkg);  }  off_t SYMEXPORT alpm_pkg_get_size(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(-1)); -	ASSERT(pkg != NULL, return(-1)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->size; +	return pkg->ops->get_size(pkg);  }  off_t SYMEXPORT alpm_pkg_get_isize(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(-1)); -	ASSERT(pkg != NULL, return(-1)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->isize; +	return pkg->ops->get_isize(pkg);  }  pmpkgreason_t SYMEXPORT alpm_pkg_get_reason(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(-1)); -	ASSERT(pkg != NULL, return(-1)); +	return pkg->ops->get_reason(pkg); +} -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->reason; +int SYMEXPORT alpm_pkg_get_epoch(pmpkg_t *pkg) +{ +	return pkg->ops->get_epoch(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->licenses; +	return pkg->ops->get_licenses(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->groups; -} - -int SYMEXPORT alpm_pkg_has_force(pmpkg_t *pkg) -{ -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(-1)); -	ASSERT(pkg != NULL, return(-1)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->force; +	return pkg->ops->get_groups(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_depends(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS); -	} -	return pkg->depends; +	return pkg->ops->get_depends(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS); -	} -	return pkg->optdepends; +	return pkg->ops->get_optdepends(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS); -	} -	return pkg->conflicts; +	return pkg->ops->get_conflicts(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_provides(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS); -	} -	return pkg->provides; +	return pkg->ops->get_provides(pkg);  } -alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg) +alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DELTAS)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS); -	} -	return pkg->deltas; +	return pkg->ops->get_replaces(pkg);  } -alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg) +alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->replaces; +	return pkg->ops->get_deltas(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_files(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local -		 && !(pkg->infolevel & INFRQ_FILES)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); -	} -	return pkg->files; +	return pkg->ops->get_files(pkg);  }  alpm_list_t SYMEXPORT *alpm_pkg_get_backup(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local -		 && !(pkg->infolevel & INFRQ_FILES)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); -	} -	return pkg->backup; +	return pkg->ops->get_backup(pkg);  }  pmdb_t SYMEXPORT *alpm_pkg_get_db(pmpkg_t *pkg)  {  	/* Sanity checks */  	ASSERT(pkg != NULL, return(NULL)); -	ASSERT(pkg->origin == PKG_FROM_CACHE, return(NULL)); +	ASSERT(pkg->origin != PKG_FROM_FILE, return(NULL));  	return(pkg->origin_data.db);  } @@ -441,83 +297,31 @@ pmdb_t SYMEXPORT *alpm_pkg_get_db(pmpkg_t *pkg)   */  void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(NULL)); -	ASSERT(pkg != NULL, return(NULL)); - -	if(pkg->origin == PKG_FROM_CACHE) { -		char clfile[PATH_MAX]; -		snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog", -				alpm_option_get_dbpath(), -				alpm_db_get_name(handle->db_local), -				alpm_pkg_get_name(pkg), -				alpm_pkg_get_version(pkg)); -		return fopen(clfile, "r"); -	} else if(pkg->origin == PKG_FROM_FILE) { -		struct archive *archive = NULL; -		struct archive_entry *entry; -		const char *pkgfile = pkg->origin_data.file; - -		if((archive = archive_read_new()) == NULL) { -			RET_ERR(PM_ERR_LIBARCHIVE, NULL); -		} - -		archive_read_support_compression_all(archive); -		archive_read_support_format_all(archive); - -		if (archive_read_open_filename(archive, pkgfile, -					ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { -			RET_ERR(PM_ERR_PKG_OPEN, NULL); -		} - -		while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { -			const char *entry_name = archive_entry_pathname(entry); - -			if(strcmp(entry_name, ".CHANGELOG") == 0) { -				return(archive); -			} -		} -		/* we didn't find a changelog */ -		archive_read_finish(archive); -		errno = ENOENT; -	} -	return(NULL); +	return pkg->ops->changelog_open(pkg);  }  /**   * Read data from an open changelog 'file stream'. Similar to fread in - * functionality, this function takes a buffer and amount of data to read. + * functionality, this function takes a buffer and amount of data to read. If an + * error occurs pm_errno will be set. + *   * @param ptr a buffer to fill with raw changelog data   * @param size the size of the buffer   * @param pkg the package that the changelog is being read from   * @param fp a 'file stream' to the package changelog - * @return the number of characters read, or 0 if there is no more data + * @return the number of characters read, or 0 if there is no more data or an + * error occurred.   */  size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,  		const pmpkg_t *pkg, const void *fp)  { -	size_t ret = 0; -	if(pkg->origin == PKG_FROM_CACHE) { -		ret = fread(ptr, 1, size, (FILE*)fp); -	} else if(pkg->origin == PKG_FROM_FILE) { -		ret = archive_read_data((struct archive*)fp, ptr, size); -	} -	return(ret); +	return pkg->ops->changelog_read(ptr, size, pkg, fp);  }  /*  int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)  { -	int ret = 0; -	if(pkg->origin == PKG_FROM_CACHE) { -		ret = feof((FILE*)fp); -	} else if(pkg->origin == PKG_FROM_FILE) { -		// note: this doesn't quite work, no feof in libarchive -		ret = archive_read_data((struct archive*)fp, NULL, 0); -	} -	return(ret); +	return pkg->ops->changelog_feof(pkg, fp);  }  */ @@ -531,28 +335,12 @@ int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)   */  int SYMEXPORT alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp)  { -	int ret = 0; -	if(pkg->origin == PKG_FROM_CACHE) { -		ret = fclose((FILE*)fp); -	} else if(pkg->origin == PKG_FROM_FILE) { -		ret = archive_read_finish((struct archive *)fp); -	} -	return(ret); +	return pkg->ops->changelog_close(pkg, fp);  }  int SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg)  { -	ALPM_LOG_FUNC; - -	/* Sanity checks */ -	ASSERT(handle != NULL, return(-1)); -	ASSERT(pkg != NULL, return(-1)); - -	if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local -		 && !(pkg->infolevel & INFRQ_SCRIPTLET)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET); -	} -	return pkg->scriptlet; +	return pkg->ops->has_scriptlet(pkg);  }  static void find_requiredby(pmpkg_t *pkg, pmdb_t *db, alpm_list_t **reqs) @@ -626,6 +414,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)  	CALLOC(newpkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL)); +	newpkg->name_hash = pkg->name_hash;  	STRDUP(newpkg->filename, pkg->filename, RET_ERR(PM_ERR_MEMORY, newpkg));  	STRDUP(newpkg->name, pkg->name, RET_ERR(PM_ERR_MEMORY, newpkg));  	STRDUP(newpkg->version, pkg->version, RET_ERR(PM_ERR_MEMORY, newpkg)); @@ -639,7 +428,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)  	newpkg->size = pkg->size;  	newpkg->isize = pkg->isize;  	newpkg->scriptlet = pkg->scriptlet; -	newpkg->force = pkg->force; +	newpkg->epoch = pkg->epoch;  	newpkg->reason = pkg->reason;  	newpkg->licenses   = alpm_list_strdup(pkg->licenses); @@ -657,6 +446,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)  	/* internal */  	newpkg->origin = pkg->origin; +	newpkg->ops = pkg->ops;  	if(newpkg->origin == PKG_FROM_FILE) {  		newpkg->origin_data.file = strdup(pkg->origin_data.file);  	} else { @@ -726,21 +516,25 @@ void _alpm_pkg_free_trans(pmpkg_t *pkg)  	pkg->removes = NULL;  } -/* Is spkg an upgrade for locapkg? */ +/* Is spkg an upgrade for localpkg? */  int _alpm_pkg_compare_versions(pmpkg_t *spkg, pmpkg_t *localpkg)  { -	int cmp = 0; +	int spkg_epoch, localpkg_epoch;  	ALPM_LOG_FUNC; -	cmp = alpm_pkg_vercmp(alpm_pkg_get_version(spkg), -			alpm_pkg_get_version(localpkg)); +	spkg_epoch = alpm_pkg_get_epoch(spkg); +	localpkg_epoch = alpm_pkg_get_epoch(localpkg); -	if(cmp < 0 && alpm_pkg_has_force(spkg)) { -		cmp = 1; +	if(spkg_epoch > localpkg_epoch) { +		return(1); +	} else if(spkg_epoch < localpkg_epoch) { +		return(-1);  	} -	return(cmp); +	/* equal epoch values, move on to version comparison */ +	return alpm_pkg_vercmp(alpm_pkg_get_version(spkg), +			alpm_pkg_get_version(localpkg));  }  /* Helper function for comparing packages @@ -749,7 +543,7 @@ int _alpm_pkg_cmp(const void *p1, const void *p2)  {  	pmpkg_t *pkg1 = (pmpkg_t *)p1;  	pmpkg_t *pkg2 = (pmpkg_t *)p2; -	return(strcmp(pkg1->name, pkg2->name)); +	return(strcoll(pkg1->name, pkg2->name));  }  /* Test for existence of a package in a alpm_list_t* @@ -758,6 +552,7 @@ int _alpm_pkg_cmp(const void *p1, const void *p2)  pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle)  {  	alpm_list_t *lp; +	unsigned long needle_hash;  	ALPM_LOG_FUNC; @@ -765,11 +560,21 @@ pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle)  		return(NULL);  	} +	needle_hash = _alpm_hash_sdbm(needle); +  	for(lp = haystack; lp; lp = lp->next) {  		pmpkg_t *info = lp->data; -		if(info && strcmp(info->name, needle) == 0) { -			return(info); +		if(info) { +			/* a zero hash will cause a fall-through just in case */ +			if(info->name_hash && info->name_hash != needle_hash) { +				continue; +			} + +			/* finally: we had hash match, verify string match */ +			if(strcmp(info->name, needle) == 0) { +				return(info); +			}  		}  	}  	return(NULL); diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index c8946448..7740d79a 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -31,27 +31,94 @@  #include "db.h"  typedef enum _pmpkgfrom_t { -	PKG_FROM_CACHE = 1, -	PKG_FROM_FILE +	PKG_FROM_FILE = 1, +	PKG_FROM_LOCALDB, +	PKG_FROM_SYNCDB  } pmpkgfrom_t; +/** Package operations struct. This struct contains function pointers to + * all methods used to access data in a package to allow for things such + * as lazy package intialization (such as used by the file backend). Each + * backend is free to define a stuct containing pointers to a specific + * implementation of these methods. Some backends may find using the + * defined default_pkg_ops struct to work just fine for their needs. + */ +struct pkg_operations { +	const char *(*get_filename) (pmpkg_t *); +	const char *(*get_name) (pmpkg_t *); +	const char *(*get_version) (pmpkg_t *); +	const char *(*get_desc) (pmpkg_t *); +	const char *(*get_url) (pmpkg_t *); +	time_t (*get_builddate) (pmpkg_t *); +	time_t (*get_installdate) (pmpkg_t *); +	const char *(*get_packager) (pmpkg_t *); +	const char *(*get_md5sum) (pmpkg_t *); +	const char *(*get_arch) (pmpkg_t *); +	off_t (*get_size) (pmpkg_t *); +	off_t (*get_isize) (pmpkg_t *); +	pmpkgreason_t (*get_reason) (pmpkg_t *); +	int (*get_epoch) (pmpkg_t *); +	int (*has_scriptlet) (pmpkg_t *); + +	alpm_list_t *(*get_licenses) (pmpkg_t *); +	alpm_list_t *(*get_groups) (pmpkg_t *); +	alpm_list_t *(*get_depends) (pmpkg_t *); +	alpm_list_t *(*get_optdepends) (pmpkg_t *); +	alpm_list_t *(*get_conflicts) (pmpkg_t *); +	alpm_list_t *(*get_provides) (pmpkg_t *); +	alpm_list_t *(*get_replaces) (pmpkg_t *); +	alpm_list_t *(*get_deltas) (pmpkg_t *); +	alpm_list_t *(*get_files) (pmpkg_t *); +	alpm_list_t *(*get_backup) (pmpkg_t *); + +	void *(*changelog_open) (pmpkg_t *); +	size_t (*changelog_read) (void *, size_t, const pmpkg_t *, const void *); +	int (*changelog_close) (const pmpkg_t *, void *); + +	/* still to add: +	 * checkmd5sum() ? +	 * compute_requiredby() +	 */ +}; + +/** The standard package operations struct. get fields directly from the + * struct itself with no abstraction layer or any type of lazy loading. + * The actual definition is in package.c so it can have access to the + * default accessor functions which are defined there. + */ +extern struct pkg_operations default_pkg_ops; +  struct __pmpkg_t { +	unsigned long name_hash;  	char *filename;  	char *name;  	char *version;  	char *desc;  	char *url; -	time_t builddate; -	time_t installdate;  	char *packager;  	char *md5sum;  	char *arch; + +	time_t builddate; +	time_t installdate; +  	off_t size;  	off_t isize;  	off_t download_size; +  	int scriptlet; -	int force; +	int epoch; +  	pmpkgreason_t reason; +	pmpkgfrom_t origin; +	/* origin == PKG_FROM_FILE, use pkg->origin_data.file +	 * origin == PKG_FROM_*DB, use pkg->origin_data.db */ +	union { +		pmdb_t *db; +		char *file; +	} origin_data; +	pmdbinfrq_t infolevel; +  	alpm_list_t *licenses;  	alpm_list_t *replaces;  	alpm_list_t *groups; @@ -64,17 +131,8 @@ struct __pmpkg_t {  	alpm_list_t *deltas;  	alpm_list_t *delta_path;  	alpm_list_t *removes; /* in transaction targets only */ -	/* internal */ -	pmpkgfrom_t origin; -	/* Replaced 'void *data' with this union as follows: -  origin == PKG_FROM_CACHE, use pkg->origin_data.db -  origin == PKG_FROM_FILE, use pkg->origin_data.file -	*/ -  union { -		pmdb_t *db; -		char *file; -	} origin_data; -	pmdbinfrq_t infolevel; + +	struct pkg_operations *ops;  };  pmpkg_t* _alpm_pkg_new(void); diff --git a/lib/libalpm/po/Makefile.in.in b/lib/libalpm/po/Makefile.in.in index 6f2e2e94..83d8838a 100644 --- a/lib/libalpm/po/Makefile.in.in +++ b/lib/libalpm/po/Makefile.in.in @@ -1,5 +1,5 @@  # Makefile for PO directory in any package using GNU gettext. -# Copyright (C) 1995-1997, 2000-2003 by Ulrich Drepper <drepper@gnu.ai.mit.edu> +# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu>  #  # This file can be copied and used freely without restrictions.  It can  # be used in projects which are not available under the GNU General Public @@ -8,10 +8,12 @@  # Please note that the actual code of GNU gettext is covered by the GNU  # General Public License and is *not* in the public domain.  # -# Origin: gettext-0.13 +# Origin: gettext-0.18 +GETTEXT_MACRO_VERSION = 0.18  PACKAGE = @PACKAGE@  VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@  SHELL = /bin/sh  @SET_MAKE@ @@ -22,18 +24,38 @@ VPATH = @srcdir@  prefix = @prefix@  exec_prefix = @exec_prefix@ -datadir = @datadir@  datarootdir = @datarootdir@ -localedir = $(datadir)/locale +datadir = @datadir@ +localedir = @localedir@  gettextsrcdir = $(datadir)/gettext/po  INSTALL = @INSTALL@  INSTALL_DATA = @INSTALL_DATA@ -mkinstalldirs = @INSTALL@ -d -GMSGFMT = @GMSGFMT@ -MSGFMT = @MSGFMT@ -XGETTEXT = @XGETTEXT@ +# We use $(mkdir_p). +# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as +# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, +# @install_sh@ does not start with $(SHELL), so we add it. +# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined +# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake +# versions, $(mkinstalldirs) and $(install_sh) are unused. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +mkdir_p = @mkdir_p@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))  MSGMERGE = msgmerge  MSGMERGE_UPDATE = @MSGMERGE@ --update  MSGINIT = msginit @@ -46,7 +68,7 @@ UPDATEPOFILES = @UPDATEPOFILES@  DUMMYPOFILES = @DUMMYPOFILES@  DISTFILES.common = Makefile.in.in remove-potcdate.sin \  $(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) -DISTFILES = $(DISTFILES.common) Makevars POTFILES.in $(DOMAIN).pot stamp-po \ +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \  $(POFILES) $(GMOFILES) \  $(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) @@ -57,7 +79,7 @@ CATALOGS = @CATALOGS@  # Makevars gets inserted here. (Don't remove this line!)  .SUFFIXES: -.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-update +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update  .po.mo:  	@echo "$(MSGFMT) -c -o $@ $<"; \ @@ -66,19 +88,32 @@ CATALOGS = @CATALOGS@  .po.gmo:  	@lang=`echo $* | sed -e 's,.*/,,'`; \  	test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ -	echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ -	cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo +	echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ +	cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo  .sin.sed:  	sed -e '/^#/d' $< > t-$@  	mv t-$@ $@ -all: all-@USE_NLS@ +all: check-macro-version all-@USE_NLS@  all-yes: stamp-po  all-no: +# Ensure that the gettext macros and this Makefile.in.in are in sync. +check-macro-version: +	@test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ +	  || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ +	       exit 1; \ +	     } + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). +  # stamp-po is a timestamp denoting the last time at which the CATALOGS have  # been loosely updated. Its purpose is that when a developer or translator  # checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, @@ -88,10 +123,13 @@ all-no:  # $(POFILES) has been designed to not touch files that don't need to be  # changed.  stamp-po: $(srcdir)/$(DOMAIN).pot -	test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) -	@echo "touch stamp-po" -	@echo timestamp > stamp-poT -	@mv stamp-poT stamp-po +	test ! -f $(srcdir)/$(DOMAIN).pot || \ +	  test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) +	@test ! -f $(srcdir)/$(DOMAIN).pot || { \ +	  echo "touch stamp-po" && \ +	  echo timestamp > stamp-poT && \ +	  mv stamp-poT stamp-po; \ +	}  # Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',  # otherwise packages like GCC can not be built if only parts of the source @@ -100,11 +138,34 @@ stamp-po: $(srcdir)/$(DOMAIN).pot  # This target rebuilds $(DOMAIN).pot; it is an expensive operation.  # Note that $(DOMAIN).pot is not touched if it doesn't need to be changed.  $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed -	$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ -	  --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ -	  --files-from=$(srcdir)/POTFILES.in \ -	  --copyright-holder='$(COPYRIGHT_HOLDER)' \ -	  --msgid-bugs-address='$(MSGID_BUGS_ADDRESS)' +	if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \ +	  package_gnu='GNU '; \ +	else \ +	  package_gnu=''; \ +	fi; \ +	if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ +	  msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ +	else \ +	  msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ +	fi; \ +	case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ +	  '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ +	    $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ +	      --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ +	      --files-from=$(srcdir)/POTFILES.in \ +	      --copyright-holder='$(COPYRIGHT_HOLDER)' \ +	      --msgid-bugs-address="$$msgid_bugs_address" \ +	    ;; \ +	  *) \ +	    $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ +	      --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ +	      --files-from=$(srcdir)/POTFILES.in \ +	      --copyright-holder='$(COPYRIGHT_HOLDER)' \ +	      --package-name="$${package_gnu}@PACKAGE@" \ +	      --package-version='@VERSION@' \ +	      --msgid-bugs-address="$$msgid_bugs_address" \ +	    ;; \ +	esac  	test ! -f $(DOMAIN).po || { \  	  if test -f $(srcdir)/$(DOMAIN).pot; then \  	    sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ @@ -130,16 +191,27 @@ $(srcdir)/$(DOMAIN).pot:  # Note that a PO file is not touched if it doesn't need to be changed.  $(POFILES): $(srcdir)/$(DOMAIN).pot  	@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ -	test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ -	echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ -	cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot +	if test -f "$(srcdir)/$${lang}.po"; then \ +	  test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ +	  echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ +	  cd $(srcdir) \ +	    && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ +	           '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ +	             $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ +	           *) \ +	             $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ +	         esac; \ +	       }; \ +	else \ +	  $(MAKE) $${lang}.po-create; \ +	fi  install: install-exec install-data  install-exec:  install-data: install-data-@USE_NLS@  	if test "$(PACKAGE)" = "gettext-tools"; then \ -	  $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ +	  $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \  	  for file in $(DISTFILES.common) Makevars.template; do \  	    $(INSTALL_DATA) $(srcdir)/$$file \  			    $(DESTDIR)$(gettextsrcdir)/$$file; \ @@ -152,13 +224,12 @@ install-data: install-data-@USE_NLS@  	fi  install-data-no: all  install-data-yes: all -	$(mkinstalldirs) $(DESTDIR)$(datadir)  	@catalogs='$(CATALOGS)'; \  	for cat in $$catalogs; do \  	  cat=`basename $$cat`; \  	  lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \  	  dir=$(localedir)/$$lang/LC_MESSAGES; \ -	  $(mkinstalldirs) $(DESTDIR)$$dir; \ +	  $(mkdir_p) $(DESTDIR)$$dir; \  	  if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \  	  $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \  	  echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ @@ -198,19 +269,18 @@ installdirs: installdirs-exec installdirs-data  installdirs-exec:  installdirs-data: installdirs-data-@USE_NLS@  	if test "$(PACKAGE)" = "gettext-tools"; then \ -	  $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ +	  $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \  	else \  	  : ; \  	fi  installdirs-data-no:  installdirs-data-yes: -	$(mkinstalldirs) $(DESTDIR)$(datadir)  	@catalogs='$(CATALOGS)'; \  	for cat in $$catalogs; do \  	  cat=`basename $$cat`; \  	  lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \  	  dir=$(localedir)/$$lang/LC_MESSAGES; \ -	  $(mkinstalldirs) $(DESTDIR)$$dir; \ +	  $(mkdir_p) $(DESTDIR)$$dir; \  	  for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \  	    if test -n "$$lc"; then \  	      if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ @@ -285,11 +355,14 @@ dist distdir:  	$(MAKE) update-po  	@$(MAKE) dist2  # This is a separate target because 'update-po' must be executed before. -dist2: $(DISTFILES) +dist2: stamp-po $(DISTFILES)  	dists="$(DISTFILES)"; \  	if test "$(PACKAGE)" = "gettext-tools"; then \  	  dists="$$dists Makevars.template"; \  	fi; \ +	if test -f $(srcdir)/$(DOMAIN).pot; then \ +	  dists="$$dists $(DOMAIN).pot stamp-po"; \ +	fi; \  	if test -f $(srcdir)/ChangeLog; then \  	  dists="$$dists ChangeLog"; \  	fi; \ @@ -301,9 +374,9 @@ dist2: $(DISTFILES)  	if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \  	for file in $$dists; do \  	  if test -f $$file; then \ -	    cp -p $$file $(distdir); \ +	    cp -p $$file $(distdir) || exit 1; \  	  else \ -	    cp -p $(srcdir)/$$file $(distdir); \ +	    cp -p $(srcdir)/$$file $(distdir) || exit 1; \  	  fi; \  	done @@ -312,6 +385,13 @@ update-po: Makefile  	test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)  	$(MAKE) update-gmo +# General rule for creating PO files. + +.nop.po-create: +	@lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ +	echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ +	exit 1 +  # General rule for updating PO files.  .nop.po-update: @@ -320,9 +400,15 @@ update-po: Makefile  	tmpdir=`pwd`; \  	echo "$$lang:"; \  	test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ -	echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ +	echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \  	cd $(srcdir); \ -	if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ +	if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ +	       '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ +	         $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ +	       *) \ +	         $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ +	     esac; \ +	   }; then \  	  if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \  	    rm -f $$tmpdir/$$lang.new.po; \  	  else \ @@ -343,10 +429,13 @@ $(DUMMYPOFILES):  update-gmo: Makefile $(GMOFILES)  	@: -Makefile: Makefile.in.in $(top_builddir)/config.status @POMAKEFILEDEPS@ +# Recreate Makefile by invoking config.status. Explicitly invoke the shell, +# because execution permission bits may not work on the current file system. +# Use @SHELL@, which is the shell determined by autoconf for the use by its +# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@  	cd $(top_builddir) \ -	  && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ -	       $(SHELL) ./config.status +	  && @SHELL@ ./config.status $(subdir)/$@.in po-directories  force: diff --git a/lib/libalpm/po/POTFILES.in b/lib/libalpm/po/POTFILES.in index 475cf4b4..65637977 100644 --- a/lib/libalpm/po/POTFILES.in +++ b/lib/libalpm/po/POTFILES.in @@ -6,8 +6,9 @@ lib/libalpm/add.c  lib/libalpm/alpm.c  #lib/libalpm/alpm_list.c  lib/libalpm/backup.c -lib/libalpm/be_files.c +lib/libalpm/be_local.c  lib/libalpm/be_package.c +lib/libalpm/be_sync.c  lib/libalpm/cache.c  lib/libalpm/conflict.c  lib/libalpm/db.c diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 153c0426..0bcf5521 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -42,7 +42,6 @@  #include "backup.h"  #include "package.h"  #include "db.h" -#include "cache.h"  #include "deps.h"  #include "handle.h"  #include "alpm.h" @@ -311,6 +310,10 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra  	_alpm_log(PM_LOG_DEBUG, "removing old package first (%s-%s)\n",  			oldpkg->name, oldpkg->version); +	if(trans->flags & PM_TRANS_FLAG_DBONLY) { +		goto db; +	} +  	/* copy the remove skiplist over */  	skip_remove =  		alpm_list_join(alpm_list_strdup(trans->skip_remove),alpm_list_strdup(handle->noupgrade)); @@ -345,10 +348,11 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra  	alpm_list_free(newfiles);  	FREELIST(skip_remove); +db:  	/* remove the package from the database */  	_alpm_log(PM_LOG_DEBUG, "updating database\n");  	_alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname); -	if(_alpm_db_remove(handle->db_local, oldpkg) == -1) { +	if(_alpm_local_db_remove(handle->db_local, oldpkg) == -1) {  		_alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),  				pkgname, alpm_pkg_get_version(oldpkg));  	} @@ -447,7 +451,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)  		/* remove the package from the database */  		_alpm_log(PM_LOG_DEBUG, "updating database\n");  		_alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname); -		if(_alpm_db_remove(db, info) == -1) { +		if(_alpm_local_db_remove(db, info) == -1) {  			_alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),  			          pkgname, alpm_pkg_get_version(info));  		} diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 57097fd1..8af32e45 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -31,7 +31,6 @@  #include <stdint.h> /* intmax_t */  #include <unistd.h>  #include <time.h> -#include <dirent.h>  /* libalpm */  #include "sync.h" @@ -39,7 +38,6 @@  #include "log.h"  #include "package.h"  #include "db.h" -#include "cache.h"  #include "deps.h"  #include "conflict.h"  #include "trans.h" @@ -50,6 +48,7 @@  #include "dload.h"  #include "delta.h"  #include "remove.h" +#include "diskspace.h"  /** Check for new version of pkg in sync repos   * (only the first occurrence is considered in sync) @@ -529,10 +528,10 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync  			/* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */  			pmdepend_t *dep1 = _alpm_splitdep(conflict->package1);  			pmdepend_t *dep2 = _alpm_splitdep(conflict->package2); -			if(alpm_depcmp(sync1, dep2)) { +			if(_alpm_depcmp(sync1, dep2)) {  				rsync = sync2;  				sync = sync1; -			} else if(alpm_depcmp(sync2, dep1)) { +			} else if(_alpm_depcmp(sync2, dep1)) {  				rsync = sync1;  				sync = sync2;  			} else { @@ -834,7 +833,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)  		for(j = trans->add; j; j = j->next) {  			pmpkg_t *spkg = j->data; -			if(spkg->origin == PKG_FROM_CACHE && current == spkg->origin_data.db) { +			if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) {  				const char *fname = NULL;  				fname = alpm_pkg_get_filename(spkg); @@ -998,6 +997,19 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)  		EVENT(trans, PM_TRANS_EVT_FILECONFLICTS_DONE, NULL, NULL);  	} +	/* check available disk space */ +	if(handle->checkspace) { +		EVENT(trans, PM_TRANS_EVT_DISKSPACE_START, NULL, NULL); + +		_alpm_log(PM_LOG_DEBUG, "checking available disk space\n"); +		if(_alpm_check_diskspace(trans, handle->db_local) == -1) { +			_alpm_log(PM_LOG_ERROR, _("not enough free disk space\n")); +			goto error; +		} + +		EVENT(trans, PM_TRANS_EVT_DISKSPACE_DONE, NULL, NULL); +	} +  	/* remove conflicting and to-be-replaced packages */  	if(replaces) {  		_alpm_log(PM_LOG_DEBUG, "removing conflicting and to-be-replaced packages\n"); diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index 02612ec1..5bc2c911 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -44,7 +44,6 @@  #include "sync.h"  #include "alpm.h"  #include "deps.h" -#include "cache.h"  /** \addtogroup alpm_trans Transaction Functions   * @brief Functions to manipulate libalpm transactions @@ -323,11 +322,11 @@ static int grep(const char *fn, const char *needle)  	}  	while(!feof(fp)) {  		char line[1024]; -		int sline = sizeof(line)-1; -		fgets(line, sline, fp); -		if(feof(fp)) { +		if(fgets(line, sizeof(line), fp) == NULL) {  			continue;  		} +		/* TODO: this will not work if the search string +		 * ends up being split across line reads */  		if(strstr(line, needle)) {  			fclose(fp);  			return(1); @@ -344,6 +343,7 @@ int _alpm_runscriptlet(const char *root, const char *installfn,  	char scriptfn[PATH_MAX];  	char cmdline[PATH_MAX];  	char tmpdir[PATH_MAX]; +	char *argv[] = { "sh", "-c", cmdline, NULL };  	char *scriptpath;  	int clean_tmpdir = 0;  	int retval = 0; @@ -371,7 +371,7 @@ int _alpm_runscriptlet(const char *root, const char *installfn,  	/* either extract or copy the scriptlet */  	snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir); -	if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) { +	if(strcmp(script, "pre_upgrade") == 0 || strcmp(script, "pre_install") == 0) {  		if(_alpm_unpack_single(installfn, tmpdir, ".INSTALL")) {  			retval = 1;  		} @@ -401,7 +401,9 @@ int _alpm_runscriptlet(const char *root, const char *installfn,  				scriptpath, script, ver);  	} -	retval = _alpm_run_chroot(root, cmdline); +	_alpm_log(PM_LOG_DEBUG, "executing \"%s\"\n", cmdline); + +	retval = _alpm_run_chroot(root, "/bin/sh", argv);  cleanup:  	if(clean_tmpdir && _alpm_rmrf(tmpdir)) { diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 32eaa442..1291ea0f 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -43,13 +43,18 @@  #include <archive.h>  #include <archive_entry.h> +#ifdef HAVE_LIBSSL +#include <openssl/md5.h> +#else +#include "md5.h" +#endif +  /* libalpm */  #include "util.h"  #include "log.h"  #include "package.h"  #include "alpm.h"  #include "alpm_list.h" -#include "md5.h"  #include "handle.h"  #ifndef HAVE_STRSEP @@ -143,7 +148,15 @@ int _alpm_copyfile(const char *src, const char *dest)  	/* do the actual file copy */  	while((len = fread(buf, 1, CPBUFSIZE, in))) { -		fwrite(buf, 1, len, out); +		size_t nwritten = 0; +		nwritten = fwrite(buf, 1, len, out); +		if((nwritten != len) || ferror(out)) { +			pm_errno = PM_ERR_WRITE; +			_alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"), +					dest, strerror(errno)); +			ret = -1; +			goto cleanup; +		}  	}  	/* chmod dest to permissions of src, as long as it is not a symlink */ @@ -347,7 +360,7 @@ int _alpm_unpack(const char *archive, const char *prefix, alpm_list_t *list, int  		int readret = archive_read_extract(_archive, entry, 0);  		if(readret == ARCHIVE_WARN) {  			/* operation succeeded but a non-critical error was encountered */ -			_alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", +			_alpm_log(PM_LOG_WARNING, _("warning given while extracting %s (%s)\n"),  					entryname, archive_error_string(_archive));  		} else if(readret != ARCHIVE_OK) {  			_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), @@ -364,8 +377,8 @@ int _alpm_unpack(const char *archive, const char *prefix, alpm_list_t *list, int  cleanup:  	umask(oldmask);  	archive_read_finish(_archive); -	if(restore_cwd) { -		chdir(cwd); +	if(restore_cwd && chdir(cwd) != 0) { +		_alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));  	}  	return(ret);  } @@ -398,7 +411,7 @@ int _alpm_rmrf(const char *path)  			for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {  				if(dp->d_ino) {  					sprintf(name, "%s/%s", path, dp->d_name); -					if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) { +					if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) {  						errflag += _alpm_rmrf(name);  					}  				} @@ -444,10 +457,11 @@ int _alpm_logaction(int usesyslog, FILE *f, const char *fmt, va_list args)  	return(ret);  } -int _alpm_run_chroot(const char *root, const char *cmd) +int _alpm_run_chroot(const char *root, const char *path, char *const argv[])  {  	char cwd[PATH_MAX];  	pid_t pid; +	int pipefd[2];  	int restore_cwd = 0;  	int retval = 0; @@ -466,11 +480,17 @@ int _alpm_run_chroot(const char *root, const char *cmd)  		goto cleanup;  	} -	_alpm_log(PM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", cmd, root); +	_alpm_log(PM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", path, root);  	/* Flush open fds before fork() to avoid cloning buffers */  	fflush(NULL); +	if(pipe(pipefd) == -1) { +		_alpm_log(PM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno)); +		retval = 1; +		goto cleanup; +	} +  	/* fork- parent and child each have seperate code blocks below */  	pid = fork();  	if(pid == -1) { @@ -480,62 +500,74 @@ int _alpm_run_chroot(const char *root, const char *cmd)  	}  	if(pid == 0) { -		FILE *pipe;  		/* this code runs for the child only (the actual chroot/exec) */ -		_alpm_log(PM_LOG_DEBUG, "chrooting in %s\n", root); +		close(1); +		close(2); +		while(dup2(pipefd[1], 1) == -1 && errno == EINTR); +		while(dup2(pipefd[1], 2) == -1 && errno == EINTR); +		close(pipefd[0]); +		close(pipefd[1]); + +		/* use fprintf instead of _alpm_log to send output through the parent */  		if(chroot(root) != 0) { -			_alpm_log(PM_LOG_ERROR, _("could not change the root directory (%s)\n"), -					strerror(errno)); +			fprintf(stderr, _("could not change the root directory (%s)\n"), strerror(errno));  			exit(1);  		}  		if(chdir("/") != 0) { -			_alpm_log(PM_LOG_ERROR, _("could not change directory to / (%s)\n"), -					strerror(errno)); +			fprintf(stderr, _("could not change directory to / (%s)\n"), strerror(errno));  			exit(1);  		}  		umask(0022); -		pipe = popen(cmd, "r"); -		if(!pipe) { -			_alpm_log(PM_LOG_ERROR, _("call to popen failed (%s)\n"), -					strerror(errno)); -			exit(1); -		} -		while(!feof(pipe)) { -			char line[PATH_MAX]; -			if(fgets(line, PATH_MAX, pipe) == NULL) -				break; -			alpm_logaction("%s", line); -			EVENT(handle->trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL); -		} -		retval = pclose(pipe); -		exit(WEXITSTATUS(retval)); +		execv(path, argv); +		fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno)); +		exit(1);  	} else {  		/* this code runs for the parent only (wait on the child) */ -		pid_t retpid;  		int status; -		do { -			retpid = waitpid(pid, &status, 0); -		} while(retpid == -1 && errno == EINTR); -		if(retpid == -1) { -			_alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"), -			          strerror(errno)); +		FILE *pipe; + +		close(pipefd[1]); +		pipe = fdopen(pipefd[0], "r"); +		if(pipe == NULL) { +			close(pipefd[0]);  			retval = 1; -			goto cleanup;  		} else { -			/* check the return status, make sure it is 0 (success) */ -			if(WIFEXITED(status)) { -				_alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n"); -				if(WEXITSTATUS(status) != 0) { -					_alpm_log(PM_LOG_ERROR, _("command failed to execute correctly\n")); -					retval = 1; -				} +			while(!feof(pipe)) { +				char line[PATH_MAX]; +				if(fgets(line, PATH_MAX, pipe) == NULL) +					break; +				alpm_logaction("%s", line); +				EVENT(handle->trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL); +			} +			fclose(pipe); +		} + +		while(waitpid(pid, &status, 0) == -1) { +			if(errno != EINTR) { +				_alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno)); +				retval = 1; +				goto cleanup; +			} +		} + +		/* report error from above after the child has exited */ +		if(retval != 0) { +			_alpm_log(PM_LOG_ERROR, _("could not open pipe (%s)\n"), strerror(errno)); +			goto cleanup; +		} +		/* check the return status, make sure it is 0 (success) */ +		if(WIFEXITED(status)) { +			_alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n"); +			if(WEXITSTATUS(status) != 0) { +				_alpm_log(PM_LOG_ERROR, _("command failed to execute correctly\n")); +				retval = 1;  			}  		}  	}  cleanup: -	if(restore_cwd) { -		chdir(cwd); +	if(restore_cwd && chdir(cwd) != 0) { +		_alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));  	}  	return(retval); @@ -551,7 +583,8 @@ int _alpm_ldconfig(const char *root)  	if(access(line, F_OK) == 0) {  		snprintf(line, PATH_MAX, "%ssbin/ldconfig", root);  		if(access(line, X_OK) == 0) { -			_alpm_run_chroot(root, "/sbin/ldconfig"); +			char *argv[] = { "ldconfig", NULL }; +			_alpm_run_chroot(root, "/sbin/ldconfig", argv);  		}  	} @@ -648,6 +681,42 @@ int _alpm_lstat(const char *path, struct stat *buf)  	return(ret);  } +#ifdef HAVE_LIBSSL +static int md5_file(const char *path, unsigned char output[16]) +{ +    FILE *f; +    size_t n; +    MD5_CTX ctx; +    unsigned char *buf; + +		CALLOC(buf, 8192, sizeof(unsigned char), return(1)); + +    if((f = fopen(path, "rb")) == NULL) { +        free(buf); +        return(1); +    } + +    MD5_Init(&ctx); + +    while((n = fread(buf, 1, sizeof(buf), f)) > 0) { +        MD5_Update(&ctx, buf, n); +		} + +    MD5_Final(output, &ctx); + +    memset(&ctx, 0, sizeof(MD5_CTX)); +    free(buf); + +    if(ferror(f) != 0) { +        fclose(f); +        return(2); +    } + +    fclose(f); +    return(0); +} +#endif +  /** Get the md5 sum of file.   * @param filename name of the file   * @return the checksum on success, NULL on error @@ -665,6 +734,7 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename)  	/* allocate 32 chars plus 1 for null */  	md5sum = calloc(33, sizeof(char)); +	/* defined above for OpenSSL, otherwise defined in md5.h */  	ret = md5_file(filename, output);  	if (ret > 0) { @@ -730,4 +800,71 @@ char *_alpm_archive_fgets(char *line, size_t size, struct archive *a)  	return(line);  } +int _alpm_splitname(const char *target, pmpkg_t *pkg) +{ +	/* the format of a db entry is as follows: +	 *    package-version-rel/ +	 * package name can contain hyphens, so parse from the back- go back +	 * two hyphens and we have split the version from the name. +	 */ +	char *tmp, *p, *q; + +	if(target == NULL || pkg == NULL) { +		return(-1); +	} +	STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1)); +	p = tmp + strlen(tmp); + +	/* remove any trailing '/' */ +	while (*(p - 1) == '/') { +	  --p; +	  *p = '\0'; +	} + +	/* do the magic parsing- find the beginning of the version string +	 * by doing two iterations of same loop to lop off two hyphens */ +	for(q = --p; *q && *q != '-'; q--); +	for(p = --q; *p && *p != '-'; p--); +	if(*p != '-' || p == tmp) { +		return(-1); +	} + +	/* copy into fields and return */ +	if(pkg->version) { +		FREE(pkg->version); +	} +	STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1)); +	/* insert a terminator at the end of the name (on hyphen)- then copy it */ +	*p = '\0'; +	if(pkg->name) { +		FREE(pkg->name); +	} +	STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1)); +	pkg->name_hash = _alpm_hash_sdbm(pkg->name); + +	free(tmp); +	return(0); +} + +/** + * Hash the given string to an unsigned long value. + * This is the standard sdbm hashing algorithm. + * @param str string to hash + * @return the hash value of the given string + */ +unsigned long _alpm_hash_sdbm(const char *str) +{ +	unsigned long hash = 0; +	int c; + +	if(!str) { +		return(hash); +	} +	while((c = *str++)) { +		hash = c + (hash << 6) + (hash << 16) - hash; +	} + +	return(hash); +} +  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 8a3154a7..0b804205 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -27,6 +27,7 @@  #include "config.h"  #include "alpm_list.h" +#include "package.h" /* pmpkg_t */  #include <stdio.h>  #include <string.h> @@ -68,7 +69,7 @@ int _alpm_unpack_single(const char *archive, const char *prefix, const char *fn)  int _alpm_unpack(const char *archive, const char *prefix, alpm_list_t *list, int breakfirst);  int _alpm_rmrf(const char *path);  int _alpm_logaction(int usesyslog, FILE *f, const char *fmt, va_list args); -int _alpm_run_chroot(const char *root, const char *cmd); +int _alpm_run_chroot(const char *root, const char *path, char *const argv[]);  int _alpm_ldconfig(const char *root);  int _alpm_str_cmp(const void *s1, const void *s2);  char *_alpm_filecache_find(const char *filename); @@ -76,6 +77,8 @@ const char *_alpm_filecache_setup(void);  int _alpm_lstat(const char *path, struct stat *buf);  int _alpm_test_md5sum(const char *filepath, const char *md5sum);  char *_alpm_archive_fgets(char *line, size_t size, struct archive *a); +int _alpm_splitname(const char *target, pmpkg_t *pkg); +unsigned long _alpm_hash_sdbm(const char *str);  #ifndef HAVE_STRSEP  char *strsep(char **, const char *); @@ -85,9 +88,6 @@ char *strsep(char **, const char *);  #define SYMEXPORT __attribute__((visibility("default")))  #define SYMHIDDEN __attribute__((visibility("internal"))) -/* max percent of package size to download deltas */ -#define MAX_DELTA_RATIO 0.7 -  #endif /* _ALPM_UTIL_H */  /* vim: set ts=2 sw=2 noet: */ | 
