diff options
Diffstat (limited to 'lib')
49 files changed, 3245 insertions, 2175 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..d4c56def 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -1,7 +1,7 @@  /*   *  add.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -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" @@ -54,7 +53,7 @@   * @param target the name of the file target to add   * @return 0 on success, -1 on error (pm_errno is set accordingly)   */ -int SYMEXPORT alpm_add_target(char *target) +int SYMEXPORT alpm_add_target(const char *target)  {  	pmpkg_t *pkg = NULL;  	const char *pkgname, *pkgver; @@ -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);  		} @@ -473,8 +477,8 @@ static int extract_single_file(struct archive *archive,  	return(errors);  } -static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, -		pmtrans_t *trans, pmdb_t *db) +static int commit_single_pkg(pmpkg_t *newpkg, size_t pkg_current, +		size_t pkg_count, pmtrans_t *trans, pmdb_t *db)  {  	int i, ret = 0, errors = 0;  	char scriptlet[PATH_MAX+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) { @@ -595,31 +605,31 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,  		}  		for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) { -			double percent; +			int percent;  			if(newpkg->size != 0) {  				/* Using compressed size for calculations here, as newpkg->isize is not  				 * exact when it comes to comparing to the ACTUAL uncompressed size  				 * (missing metadata sizes) */  				int64_t pos = archive_position_compressed(archive); -				percent = (double)pos / (double)newpkg->size; +				percent = (pos * 100) / newpkg->size;  				_alpm_log(PM_LOG_DEBUG, "decompression progress: " -						"%f%% (%"PRId64" / %jd)\n", -						percent*100.0, pos, (intmax_t)newpkg->size); -				if(percent >= 1.0) { -					percent = 1.0; +						"%d%% (%"PRId64" / %jd)\n", +						percent, pos, (intmax_t)newpkg->size); +				if(percent >= 100) { +					percent = 100;  				}  			} else { -				percent = 0.0; +				percent = 0;  			}  			if(is_upgrade) {  				PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START, -						alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count, +						alpm_pkg_get_name(newpkg), percent, pkg_count,  						pkg_current);  			} else {  				PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START, -						alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count, +						alpm_pkg_get_name(newpkg), percent, pkg_count,  						pkg_current);  			} @@ -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", @@ -705,7 +715,8 @@ cleanup:  int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)  { -	int pkg_count, pkg_current; +	size_t 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/add.h b/lib/libalpm/add.h index eb37dc78..afc7be26 100644 --- a/lib/libalpm/add.h +++ b/lib/libalpm/add.h @@ -1,7 +1,7 @@  /*   *  add.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index 51b9e25b..2a9f4605 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -1,7 +1,7 @@  /*   *  alpm.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -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..a540bc4f 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -1,7 +1,7 @@  /*   * alpm.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -97,66 +97,69 @@ typedef int (*alpm_cb_fetch)(const char *url, const char *localpath,   * Options   */ -alpm_cb_log alpm_option_get_logcb(); +alpm_cb_log alpm_option_get_logcb(void);  void alpm_option_set_logcb(alpm_cb_log cb); -alpm_cb_download alpm_option_get_dlcb(); +alpm_cb_download alpm_option_get_dlcb(void);  void alpm_option_set_dlcb(alpm_cb_download cb); -alpm_cb_fetch alpm_option_get_fetchcb(); +alpm_cb_fetch alpm_option_get_fetchcb(void);  void alpm_option_set_fetchcb(alpm_cb_fetch cb); -alpm_cb_totaldl alpm_option_get_totaldlcb(); +alpm_cb_totaldl alpm_option_get_totaldlcb(void);  void alpm_option_set_totaldlcb(alpm_cb_totaldl cb); -const char *alpm_option_get_root(); +const char *alpm_option_get_root(void);  int alpm_option_set_root(const char *root); -const char *alpm_option_get_dbpath(); +const char *alpm_option_get_dbpath(void);  int alpm_option_set_dbpath(const char *dbpath); -alpm_list_t *alpm_option_get_cachedirs(); +alpm_list_t *alpm_option_get_cachedirs(void);  int alpm_option_add_cachedir(const char *cachedir);  void alpm_option_set_cachedirs(alpm_list_t *cachedirs);  int alpm_option_remove_cachedir(const char *cachedir); -const char *alpm_option_get_logfile(); +const char *alpm_option_get_logfile(void);  int alpm_option_set_logfile(const char *logfile); -const char *alpm_option_get_lockfile(); +const char *alpm_option_get_lockfile(void);  /* no set_lockfile, path is determined from dbpath */ -int alpm_option_get_usesyslog(); +int alpm_option_get_usesyslog(void);  void alpm_option_set_usesyslog(int usesyslog); -alpm_list_t *alpm_option_get_noupgrades(); +alpm_list_t *alpm_option_get_noupgrades(void);  void alpm_option_add_noupgrade(const char *pkg);  void alpm_option_set_noupgrades(alpm_list_t *noupgrade);  int alpm_option_remove_noupgrade(const char *pkg); -alpm_list_t *alpm_option_get_noextracts(); +alpm_list_t *alpm_option_get_noextracts(void);  void alpm_option_add_noextract(const char *pkg);  void alpm_option_set_noextracts(alpm_list_t *noextract);  int alpm_option_remove_noextract(const char *pkg); -alpm_list_t *alpm_option_get_ignorepkgs(); +alpm_list_t *alpm_option_get_ignorepkgs(void);  void alpm_option_add_ignorepkg(const char *pkg);  void alpm_option_set_ignorepkgs(alpm_list_t *ignorepkgs);  int alpm_option_remove_ignorepkg(const char *pkg); -alpm_list_t *alpm_option_get_ignoregrps(); +alpm_list_t *alpm_option_get_ignoregrps(void);  void alpm_option_add_ignoregrp(const char *grp);  void alpm_option_set_ignoregrps(alpm_list_t *ignoregrps);  int alpm_option_remove_ignoregrp(const char *grp); -const char *alpm_option_get_arch(); +const char *alpm_option_get_arch(void);  void alpm_option_set_arch(const char *arch); -int alpm_option_get_usedelta(); +int alpm_option_get_usedelta(void);  void alpm_option_set_usedelta(int usedelta); -pmdb_t *alpm_option_get_localdb(); -alpm_list_t *alpm_option_get_syncdbs(); +int alpm_option_get_checkspace(void); +void alpm_option_set_checkspace(int checkspace); + +pmdb_t *alpm_option_get_localdb(void); +alpm_list_t *alpm_option_get_syncdbs(void);  /*   * Install reasons -- ie, why the package was installed @@ -235,7 +238,6 @@ 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);  off_t alpm_pkg_download_size(pmpkg_t *newpkg);  alpm_list_t *alpm_pkg_unused_deltas(pmpkg_t *pkg); @@ -368,6 +370,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 +392,9 @@ 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, +	PM_TRANS_PROGRESS_INTEGRITY_START,  } pmtransprog_t;  /* Transaction Event callback */ @@ -397,11 +405,11 @@ typedef void (*alpm_trans_cb_conv)(pmtransconv_t, void *, void *,                                     void *, int *);  /* Transaction Progress callback */ -typedef void (*alpm_trans_cb_progress)(pmtransprog_t, const char *, int, int, int); +typedef void (*alpm_trans_cb_progress)(pmtransprog_t, const char *, int, size_t, size_t); -int alpm_trans_get_flags(); -alpm_list_t * alpm_trans_get_add(); -alpm_list_t * alpm_trans_get_remove(); +int alpm_trans_get_flags(void); +alpm_list_t * alpm_trans_get_add(void); +alpm_list_t * alpm_trans_get_remove(void);  int alpm_trans_init(pmtransflag_t flags,                      alpm_trans_cb_event cb_event, alpm_trans_cb_conv conv,                      alpm_trans_cb_progress cb_progress); @@ -411,10 +419,10 @@ int alpm_trans_interrupt(void);  int alpm_trans_release(void);  int alpm_sync_sysupgrade(int enable_downgrade); -int alpm_sync_target(char *target); -int alpm_sync_dbtarget(char *db, char *target); -int alpm_add_target(char *target); -int alpm_remove_target(char *target); +int alpm_sync_target(const char *target); +int alpm_sync_dbtarget(const char *db, const char *target); +int alpm_add_target(const char *target); +int alpm_remove_target(const char *target);  /*   * Dependencies and conflicts @@ -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/alpm_list.c b/lib/libalpm/alpm_list.c index 80ba1ee7..3f9525e8 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -1,7 +1,7 @@  /*   *  alpm_list.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -269,7 +269,7 @@ alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, a   *   * @return the resultant list   */ -alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, size_t n, alpm_list_fn_cmp fn)  {  	if (n > 1) {  		alpm_list_t *left = list; @@ -511,7 +511,7 @@ inline alpm_list_t SYMEXPORT *alpm_list_first(const alpm_list_t *list)   *   * @return an alpm_list_t node for index `n`   */ -alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, int n) +alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, size_t n)  {  	const alpm_list_t *i = list;  	while(n--) { @@ -574,9 +574,9 @@ void SYMEXPORT *alpm_list_getdata(const alpm_list_t *node)   *   * @return the number of list items   */ -int SYMEXPORT alpm_list_count(const alpm_list_t *list) +size_t SYMEXPORT alpm_list_count(const alpm_list_t *list)  { -	unsigned int i = 0; +	size_t i = 0;  	const alpm_list_t *lp = list;  	while(lp) {  		++i; diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index bd639f7d..ee85a5dd 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -1,7 +1,7 @@  /*   *  alpm_list.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -56,7 +56,7 @@ alpm_list_t *alpm_list_add(alpm_list_t *list, void *data);  alpm_list_t *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn);  alpm_list_t *alpm_list_join(alpm_list_t *first, alpm_list_t *second);  alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn); -alpm_list_t *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn); +alpm_list_t *alpm_list_msort(alpm_list_t *list, size_t n, alpm_list_fn_cmp fn);  alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data);  alpm_list_t *alpm_list_remove_str(alpm_list_t *haystack, const char *needle, char **data);  alpm_list_t *alpm_list_remove_dupes(const alpm_list_t *list); @@ -67,13 +67,13 @@ alpm_list_t *alpm_list_reverse(alpm_list_t *list);  /* item accessors */  alpm_list_t *alpm_list_first(const alpm_list_t *list); -alpm_list_t *alpm_list_nth(const alpm_list_t *list, int n); +alpm_list_t *alpm_list_nth(const alpm_list_t *list, size_t n);  alpm_list_t *alpm_list_next(const alpm_list_t *list);  alpm_list_t *alpm_list_last(const alpm_list_t *list);  void *alpm_list_getdata(const alpm_list_t *entry);  /* misc */ -int alpm_list_count(const alpm_list_t *list); +size_t alpm_list_count(const alpm_list_t *list);  void *alpm_list_find(const alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn);  void *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle);  char *alpm_list_find_str(const alpm_list_t *haystack, const char *needle); diff --git a/lib/libalpm/backup.c b/lib/libalpm/backup.c index 2ef65a2b..ca955ca4 100644 --- a/lib/libalpm/backup.c +++ b/lib/libalpm/backup.c @@ -1,7 +1,7 @@  /*   *  backup.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2005 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> diff --git a/lib/libalpm/backup.h b/lib/libalpm/backup.h index 25469b90..9475aa2a 100644 --- a/lib/libalpm/backup.h +++ b/lib/libalpm/backup.h @@ -1,7 +1,7 @@  /*   *  backup.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c deleted file mode 100644 index 0ee8a3bb..00000000 --- a/lib/libalpm/be_files.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - *  be_files.c - * - *  Copyright (c) 2006 by Christian Hamar <krics@linuxforum.hu> - *  Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.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 <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <stdint.h> /* intmax_t */ -#include <sys/stat.h> -#include <dirent.h> -#include <ctype.h> -#include <time.h> -#include <limits.h> /* PATH_MAX */ -#include <locale.h> /* setlocale */ - -/* libarchive */ -#include <archive.h> -#include <archive_entry.h> - -/* 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 "deps.h" -#include "dload.h" - - -static int checkdbdir(pmdb_t *db) -{ -	struct stat buf; -	const char *path = _alpm_db_path(db); - -	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) -{ -	struct archive *_archive; -	struct archive_entry *entry; - -	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, 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); -	} - -	while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { -		const struct stat *st; -		const char *entryname; /* the name of the file in the archive */ - -		st = archive_entry_stat(entry); -		entryname = archive_entry_pathname(entry); - -		if(S_ISDIR(st->st_mode)) { -			char *name = strdup(entryname); -			*dirlist = alpm_list_add(*dirlist, name); -		} -	} -	archive_read_finish(_archive); - -	*dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); -	return(0); -} - -/* create list of directories in db */ -static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist) -{ -	DIR *dbdir; -	struct dirent *ent = NULL; -	struct stat sbuf; -	char path[PATH_MAX]; - -	dbdir = opendir(syncdbpath); -	if (dbdir != NULL) { -		while((ent = readdir(dbdir)) != NULL) { -			char *name = ent->d_name; -			size_t len; -			char *entry; - -			if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { -				continue; -			} - -			/* 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; -			} - -			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); -	} - -	*dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); -	return(0); -} - -/* remove old directories from dbdir */ -static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist) -{ -	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); -} - -/** 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, *dbfilepath; -	const char *dbpath, *syncdbpath; -	alpm_list_t *newdirlist = NULL, *olddirlist = NULL; -	alpm_list_t *onlynew = NULL, *onlyold = NULL; -	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)); -	/* 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); -	} - -	len = strlen(db->treename) + strlen(DBEXT) + 1; -	MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1)); -	sprintf(dbfile, "%s" DBEXT, db->treename); - -	dbpath = alpm_option_get_dbpath(); - -	ret = _alpm_download_single_file(dbfile, db->servers, dbpath, force); -	free(dbfile); - -	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); -	} - -	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_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew); - -		ret = remove_olddir(syncdbpath, onlyold); -		if(ret) { -			goto cleanup; -		} -	} - -	/* Cache needs to be rebuilt */ -	_alpm_db_free_pkgcache(db); - -	checkdbdir(db); -	ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0); - -cleanup: -	FREELIST(newdirlist); -	FREELIST(olddirlist); -	alpm_list_free(onlynew); -	alpm_list_free(onlyold); - -	free(dbfilepath); - -	if(ret) { -		RET_ERR(PM_ERR_SYSTEM, -1); -	} - -	return(0); -} - - -static int 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); - -	/* 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)); - -	free(tmp); -	return(0); -} - -int _alpm_db_populate(pmdb_t *db) -{ -	int count = 0; -	struct dirent *ent = NULL; -	struct stat sbuf; -	char path[PATH_MAX]; -	const char *dbpath; -	DIR *dbdir; - -	ALPM_LOG_FUNC; - -	ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); - -	dbpath = _alpm_db_path(db); -	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)) { -			continue; -		} - -		pkg = _alpm_pkg_new(); -		if(pkg == NULL) { -			closedir(dbdir); -			return(-1); -		} -		/* split the db entry name */ -		if(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_CACHE; -		pkg->origin_data.db = db; - -		/* explicitly read with only 'BASE' data, accessors will handle the rest */ -		if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) { -			_alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name); -			_alpm_pkg_free(pkg); -			continue; -		} - -		/* 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++; -	} - -	closedir(dbdir); -	db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp); -	return(count); -} - -/* Note: the return value must be freed by the caller */ -static char *get_pkgpath(pmdb_t *db, pmpkg_t *info) -{ -	size_t len; -	char *pkgpath; -	const char *dbpath; - -	dbpath = _alpm_db_path(db); -	len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3; -	MALLOC(pkgpath, len, RET_ERR(PM_ERR_MEMORY, NULL)); -	sprintf(pkgpath, "%s%s-%s/", dbpath, info->name, info->version); -	return(pkgpath); -} - -int _alpm_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 *pkgpath = NULL; - -	ALPM_LOG_FUNC; - -	if(db == NULL) { -		RET_ERR(PM_ERR_DB_NULL, -1); -	} - -	if(info == NULL || info->name == NULL || info->version == NULL) { -		_alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n"); -		return(-1); -	} - -	if(info->origin == PKG_FROM_FILE) { -		_alpm_log(PM_LOG_DEBUG, "request to read database info for a file-based package '%s', skipping...\n", info->name); -		return(-1); -	} - -	/* bitmask logic here: -	 * infolevel: 00001111 -	 * inforeq:   00010100 -	 * & result:  00000100 -	 * == to inforeq? nope, we need to load more info. */ -	if((info->infolevel & inforeq) == inforeq) { -		/* already loaded all of this info, do nothing */ -		return(0); -	} -	_alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n", -			info->name, inforeq); - -	/* clear out 'line', to be certain - and to make valgrind happy */ -	memset(line, 0, sline+1); - -	pkgpath = get_pkgpath(db, info); - -	if(access(pkgpath, F_OK)) { -		/* directory doesn't exist or can't be opened */ -		_alpm_log(PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n", -				info->name, info->version, db->treename); -		goto error; -	} - -	/* DESC */ -	if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) { -		snprintf(path, PATH_MAX, "%sdesc", 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)) { -			if(fgets(line, 256, fp) == NULL) { -				break; -			} -			_alpm_strtrim(line); -			if(strcmp(line, "%NAME%") == 0) { -				if(fgets(line, sline, fp) == NULL) { -					goto error; -				} -				if(strcmp(_alpm_strtrim(line), info->name) != 0) { -					_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name " -								"mismatch on package %s\n"), db->treename, info->name); -				} -			} else if(strcmp(line, "%VERSION%") == 0) { -				if(fgets(line, sline, 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) { -					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))) { -					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) { -					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))) { -					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) { -					goto error; -				} -				STRDUP(info->arch, _alpm_strtrim(line), goto error); -			} else if(strcmp(line, "%BUILDDATE%") == 0) { -				if(fgets(line, sline, fp) == 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); -					info->builddate = mktime(&tmp_tm); -					setlocale(LC_TIME, ""); -				} else { -					info->builddate = atol(line); -				} -			} else if(strcmp(line, "%INSTALLDATE%") == 0) { -				if(fgets(line, sline, fp) == 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); -					info->installdate = mktime(&tmp_tm); -					setlocale(LC_TIME, ""); -				} else { -					info->installdate = atol(line); -				} -			} else if(strcmp(line, "%PACKAGER%") == 0) { -				if(fgets(line, sline, fp) == NULL) { -					goto error; -				} -				STRDUP(info->packager, _alpm_strtrim(line), goto error); -			} else if(strcmp(line, "%REASON%") == 0) { -				if(fgets(line, sline, fp) == NULL) { -					goto error; -				} -				info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line)); -			} else if(strcmp(line, "%SIZE%") == 0 || 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(fgets(line, sline, 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; -				} -			} 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) { -					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; -				} -				STRDUP(info->md5sum, _alpm_strtrim(line), goto error); -			} else if(strcmp(line, "%REPLACES%") == 0) { -				while(fgets(line, sline, 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, "%FORCE%") == 0) { -				info->force = 1; -			} -		} -		fclose(fp); -		fp = NULL; -	} - -	/* FILES */ -	if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) { -		snprintf(path, PATH_MAX, "%sfiles", 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(fgets(line, 256, fp)) { -			_alpm_strtrim(line); -			if(strcmp(line, "%FILES%") == 0) { -				while(fgets(line, sline, 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))) { -					char *linedup; -					STRDUP(linedup, _alpm_strtrim(line), goto error); -					info->backup = alpm_list_add(info->backup, linedup); -				} -			} -		} -		fclose(fp); -		fp = NULL; -	} - -	/* DEPENDS */ -	if(inforeq & INFRQ_DEPENDS && !(info->infolevel & 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 && !(info->infolevel & 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 && !(info->infolevel & INFRQ_SCRIPTLET)) { -		snprintf(path, PATH_MAX, "%sinstall", pkgpath); -		if(access(path, F_OK) == 0) { -			info->scriptlet = 1; -		} -	} - -	/* internal */ -	info->infolevel |= inforeq; - -	free(pkgpath); -	return(0); - -error: -	free(pkgpath); -	if(fp) { -		fclose(fp); -	} -	return(-1); -} - -int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info) -{ -	mode_t oldmask; -	int retval = 0; -	char *pkgpath = NULL; - -	if(checkdbdir(db) != 0) { -		return(-1); -	} - -	oldmask = umask(0000); -	pkgpath = get_pkgpath(db, info); - -	if((retval = mkdir(pkgpath, 0755)) != 0) { -		_alpm_log(PM_LOG_ERROR, _("could not create directory %s: %s\n"), -				pkgpath, strerror(errno)); -	} - -	free(pkgpath); -	umask(oldmask); - -	return(retval); -} - -int _alpm_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; - -	if(db == NULL || info == NULL) { -		return(-1); -	} - -	pkgpath = get_pkgpath(db, info); - -	/* make sure we have a sane umask */ -	oldmask = umask(0022); - -	if(strcmp(db->treename, "local") == 0) { -		local = 1; -	} - -	/* DESC */ -	if(inforeq & INFRQ_DESC) { -		_alpm_log(PM_LOG_DEBUG, "writing %s-%s DESC information back to db\n", -				info->name, info->version); -		snprintf(path, PATH_MAX, "%sdesc", 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; -		} -		fprintf(fp, "%%NAME%%\n%s\n\n" -						"%%VERSION%%\n%s\n\n", info->name, info->version); -		if(info->desc) { -			fprintf(fp, "%%DESC%%\n" -							"%s\n\n", info->desc); -		} -		if(info->groups) { -			fputs("%GROUPS%\n", fp); -			for(lp = info->groups; lp; lp = lp->next) { -				fprintf(fp, "%s\n", (char *)lp->data); -			} -			fprintf(fp, "\n"); -		} -		if(info->replaces) { -			fputs("%REPLACES%\n", fp); -			for(lp = info->replaces; lp; lp = lp->next) { -				fprintf(fp, "%s\n", (char *)lp->data); -			} -			fprintf(fp, "\n"); -		} -		if(local) { -			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); -			} -		} -		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->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; -	} - -	/* 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->depends) { -			fputs("%DEPENDS%\n", fp); -			for(lp = info->depends; lp; lp = lp->next) { -				char *depstring = alpm_dep_compute_string(lp->data); -				fprintf(fp, "%s\n", depstring); -				free(depstring); -			} -			fprintf(fp, "\n"); -		} -		if(info->optdepends) { -			fputs("%OPTDEPENDS%\n", fp); -			for(lp = info->optdepends; lp; lp = lp->next) { -				fprintf(fp, "%s\n", (char *)lp->data); -			} -			fprintf(fp, "\n"); -		} -		if(info->conflicts) { -			fputs("%CONFLICTS%\n", fp); -			for(lp = info->conflicts; lp; lp = lp->next) { -				fprintf(fp, "%s\n", (char *)lp->data); -			} -			fprintf(fp, "\n"); -		} -		if(info->provides) { -			fputs("%PROVIDES%\n", fp); -			for(lp = info->provides; lp; lp = lp->next) { -				fprintf(fp, "%s\n", (char *)lp->data); -			} -			fprintf(fp, "\n"); -		} -		fclose(fp); -		fp = NULL; -	} - -	/* INSTALL */ -	/* nothing needed here (script is automatically extracted) */ - -cleanup: -	umask(oldmask); -	free(pkgpath); - -	if(fp) { -		fclose(fp); -	} - -	return(retval); -} - -int _alpm_db_remove(pmdb_t *db, pmpkg_t *info) -{ -	int ret = 0; -	char *pkgpath = NULL; - -	ALPM_LOG_FUNC; - -	if(db == NULL || info == NULL) { -		RET_ERR(PM_ERR_DB_NULL, -1); -	} - -	pkgpath = get_pkgpath(db, info); - -	ret = _alpm_rmrf(pkgpath); -	free(pkgpath); -	if(ret != 0) { -		ret = -1; -	} -	return(ret); -} - -/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c new file mode 100644 index 00000000..ea59ceca --- /dev/null +++ b/lib/libalpm/be_local.c @@ -0,0 +1,921 @@ +/* + *  be_local.c + * + *  Copyright (c) 2006-2011 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 <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> /* intmax_t */ +#include <sys/stat.h> +#include <dirent.h> +#include <time.h> +#include <limits.h> /* PATH_MAX */ +#include <locale.h> /* setlocale */ + +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> + +/* libalpm */ +#include "db.h" +#include "alpm_list.h" +#include "log.h" +#include "util.h" +#include "alpm.h" +#include "handle.h" +#include "package.h" +#include "group.h" +#include "deps.h" +#include "dload.h" + + +#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) + + +/* 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. + */ + +static const char *_cache_get_filename(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->filename; +} + +static const char *_cache_get_name(pmpkg_t *pkg) +{ +	ASSERT(pkg != NULL, return(NULL)); +	return pkg->name; +} + +static const char *_cache_get_version(pmpkg_t *pkg) +{ +	ASSERT(pkg != NULL, return(NULL)); +	return pkg->version; +} + +static const char *_cache_get_desc(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->desc; +} + +static const char *_cache_get_url(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->url; +} + +static time_t _cache_get_builddate(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, 0); +	return pkg->builddate; +} + +static time_t _cache_get_installdate(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, 0); +	return pkg->installdate; +} + +static const char *_cache_get_packager(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->packager; +} + +static const char *_cache_get_md5sum(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->md5sum; +} + +static const char *_cache_get_arch(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->arch; +} + +static off_t _cache_get_size(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->size; +} + +static off_t _cache_get_isize(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->isize; +} + +static pmpkgreason_t _cache_get_reason(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, -1); +	return pkg->reason; +} + +static alpm_list_t *_cache_get_licenses(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->licenses; +} + +static alpm_list_t *_cache_get_groups(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->groups; +} + +static int _cache_has_scriptlet(pmpkg_t *pkg) +{ +	ALPM_LOG_FUNC; + +	/* Sanity checks */ +	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; +} + +static alpm_list_t *_cache_get_depends(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->depends; +} + +static alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->optdepends; +} + +static alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->conflicts; +} + +static alpm_list_t *_cache_get_provides(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->provides; +} + +static alpm_list_t *_cache_get_replaces(pmpkg_t *pkg) +{ +	LAZY_LOAD(INFRQ_DESC, NULL); +	return pkg->replaces; +} + +/* local packages can not have deltas */ +static alpm_list_t *_cache_get_deltas(pmpkg_t *pkg) +{ +	return NULL; +} + +static alpm_list_t *_cache_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_LOCALDB +		 && !(pkg->infolevel & INFRQ_FILES)) { +		_alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); +	} +	return pkg->files; +} + +static alpm_list_t *_cache_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_LOCALDB +		 && !(pkg->infolevel & INFRQ_FILES)) { +		_alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); +	} +	return pkg->backup; +} + +/** + * 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 + */ +static void *_cache_changelog_open(pmpkg_t *pkg) +{ +	ALPM_LOG_FUNC; + +	/* 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"); +} + +/** + * 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 + */ +static size_t _cache_changelog_read(void *ptr, size_t size, +		const pmpkg_t *pkg, const void *fp) +{ +	return ( fread(ptr, 1, size, (FILE*)fp) ); +} + +/* +static 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 + */ +static int _cache_changelog_close(const pmpkg_t *pkg, void *fp) +{ +	return( fclose((FILE*)fp) ); +} + + +/** 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, +	.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      = _cache_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) +{ +	struct stat buf; +	const char *path = _alpm_db_path(db); + +	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); +} + +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)); +	} + +	return(0); +#endif +} + +static int local_db_populate(pmdb_t *db) +{ +	int count = 0; +	struct dirent *ent = NULL; +	const char *dbpath; +	DIR *dbdir; + +	ALPM_LOG_FUNC; + +	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; +		} +		if(!is_dir(dbpath, ent)) { +			continue; +		} + +		pkg = _alpm_pkg_new(); +		if(pkg == NULL) { +			closedir(dbdir); +			return(-1); +		} +		/* split the db entry name */ +		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_LOCALDB; +		pkg->origin_data.db = db; +		pkg->ops = &local_pkg_ops; + +		/* explicitly read with only 'BASE' data, accessors will handle the rest */ +		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; +		} + +		/* 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++; +	} + +	closedir(dbdir); +	db->pkgcache = alpm_list_msort(db->pkgcache, (size_t)count, _alpm_pkg_cmp); +	return(count); +} + +/* Note: the return value must be freed by the caller */ +static char *get_pkgpath(pmdb_t *db, pmpkg_t *info) +{ +	size_t len; +	char *pkgpath; +	const char *dbpath; + +	dbpath = _alpm_db_path(db); +	len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3; +	MALLOC(pkgpath, len, RET_ERR(PM_ERR_MEMORY, NULL)); +	sprintf(pkgpath, "%s%s-%s/", dbpath, info->name, info->version); +	return(pkgpath); +} + + +int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) +{ +	FILE *fp = NULL; +	char path[PATH_MAX]; +	char line[1024]; +	char *pkgpath = NULL; + +	ALPM_LOG_FUNC; + +	if(db == NULL) { +		RET_ERR(PM_ERR_DB_NULL, -1); +	} + +	if(info == NULL || info->name == NULL || info->version == NULL) { +		_alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_local_db_read, skipping\n"); +		return(-1); +	} + +	if(info->origin != PKG_FROM_LOCALDB) { +		_alpm_log(PM_LOG_DEBUG, +				"request to read info for a non-local package '%s', skipping...\n", +				info->name); +		return(-1); +	} + +	/* bitmask logic here: +	 * infolevel: 00001111 +	 * inforeq:   00010100 +	 * & result:  00000100 +	 * == to inforeq? nope, we need to load more info. */ +	if((info->infolevel & inforeq) == inforeq) { +		/* already loaded all of this info, do nothing */ +		return(0); +	} +	_alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n", +			info->name, inforeq); + +	/* clear out 'line', to be certain - and to make valgrind happy */ +	memset(line, 0, sizeof(line)); + +	pkgpath = get_pkgpath(db, info); + +	if(access(pkgpath, F_OK)) { +		/* directory doesn't exist or can't be opened */ +		_alpm_log(PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n", +				info->name, info->version, db->treename); +		goto error; +	} + +	/* DESC */ +	if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) { +		snprintf(path, PATH_MAX, "%sdesc", 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)) { +			if(fgets(line, sizeof(line), fp) == NULL) { +				break; +			} +			_alpm_strtrim(line); +			if(strcmp(line, "%NAME%") == 0) { +				if(fgets(line, sizeof(line), fp) == NULL) { +					goto error; +				} +				if(strcmp(_alpm_strtrim(line), info->name) != 0) { +					_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name " +								"mismatch on package %s\n"), db->treename, info->name); +				} +			} else if(strcmp(line, "%VERSION%") == 0) { +				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, "%DESC%") == 0) { +				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, 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, sizeof(line), fp) == NULL) { +					goto error; +				} +				STRDUP(info->url, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%LICENSE%") == 0) { +				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, sizeof(line), fp) == NULL) { +					goto error; +				} +				STRDUP(info->arch, _alpm_strtrim(line), goto error); +			} else if(strcmp(line, "%BUILDDATE%") == 0) { +				if(fgets(line, sizeof(line), fp) == NULL) { +					goto error; +				} +				_alpm_strtrim(line); +				info->builddate = _alpm_parsedate(line); +			} else if(strcmp(line, "%INSTALLDATE%") == 0) { +				if(fgets(line, sizeof(line), fp) == NULL) { +					goto error; +				} +				_alpm_strtrim(line); +				info->installdate = _alpm_parsedate(line); +			} else if(strcmp(line, "%PACKAGER%") == 0) { +				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, sizeof(line), fp) == NULL) { +					goto error; +				} +				info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line)); +			} 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, sizeof(line), fp) == NULL) { +					goto error; +				} +				info->size = atol(_alpm_strtrim(line)); +				/* 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, "%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->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); +				} +			} +		} +		fclose(fp); +		fp = NULL; +	} + +	/* FILES */ +	if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) { +		snprintf(path, PATH_MAX, "%sfiles", 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(fgets(line, sizeof(line), fp)) { +			_alpm_strtrim(line); +			if(strcmp(line, "%FILES%") == 0) { +				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, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { +					char *linedup; +					STRDUP(linedup, _alpm_strtrim(line), goto error); +					info->backup = alpm_list_add(info->backup, linedup); +				} +			} +		} +		fclose(fp); +		fp = NULL; +	} + +	/* INSTALL */ +	if(inforeq & INFRQ_SCRIPTLET && !(info->infolevel & INFRQ_SCRIPTLET)) { +		snprintf(path, PATH_MAX, "%sinstall", pkgpath); +		if(access(path, F_OK) == 0) { +			info->scriptlet = 1; +		} +	} + +	/* internal */ +	info->infolevel |= inforeq; + +	free(pkgpath); +	return(0); + +error: +	free(pkgpath); +	if(fp) { +		fclose(fp); +	} +	return(-1); +} + +int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info) +{ +	mode_t oldmask; +	int retval = 0; +	char *pkgpath = NULL; + +	if(checkdbdir(db) != 0) { +		return(-1); +	} + +	oldmask = umask(0000); +	pkgpath = get_pkgpath(db, info); + +	if((retval = mkdir(pkgpath, 0755)) != 0) { +		_alpm_log(PM_LOG_ERROR, _("could not create directory %s: %s\n"), +				pkgpath, strerror(errno)); +	} + +	free(pkgpath); +	umask(oldmask); + +	return(retval); +} + +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; +	char *pkgpath = NULL; + +	ALPM_LOG_FUNC; + +	if(db == NULL || info == NULL) { +		return(-1); +	} + +	pkgpath = get_pkgpath(db, info); + +	/* make sure we have a sane umask */ +	oldmask = umask(0022); + +	if(strcmp(db->treename, "local") != 0) { +		return(-1); +	} + +	/* DESC */ +	if(inforeq & INFRQ_DESC) { +		_alpm_log(PM_LOG_DEBUG, "writing %s-%s DESC information back to db\n", +				info->name, info->version); +		snprintf(path, PATH_MAX, "%sdesc", 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; +		} +		fprintf(fp, "%%NAME%%\n%s\n\n" +						"%%VERSION%%\n%s\n\n", info->name, info->version); +		if(info->desc) { +			fprintf(fp, "%%DESC%%\n" +							"%s\n\n", info->desc); +		} +		if(info->groups) { +			fputs("%GROUPS%\n", fp); +			for(lp = info->groups; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			fprintf(fp, "\n"); +		} +		if(info->replaces) { +			fputs("%REPLACES%\n", fp); +			for(lp = info->replaces; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			fprintf(fp, "\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); +		} +		if(info->depends) { +			fputs("%DEPENDS%\n", fp); +			for(lp = info->depends; lp; lp = lp->next) { +				char *depstring = alpm_dep_compute_string(lp->data); +				fprintf(fp, "%s\n", depstring); +				free(depstring); +			} +			fprintf(fp, "\n"); +		} +		if(info->optdepends) { +			fputs("%OPTDEPENDS%\n", fp); +			for(lp = info->optdepends; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			fprintf(fp, "\n"); +		} +		if(info->conflicts) { +			fputs("%CONFLICTS%\n", fp); +			for(lp = info->conflicts; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			fprintf(fp, "\n"); +		} +		if(info->provides) { +			fputs("%PROVIDES%\n", fp); +			for(lp = info->provides; lp; lp = lp->next) { +				fprintf(fp, "%s\n", (char *)lp->data); +			} +			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; +	} + +	/* INSTALL */ +	/* nothing needed here (script is automatically extracted) */ + +cleanup: +	umask(oldmask); +	free(pkgpath); + +	if(fp) { +		fclose(fp); +	} + +	return(retval); +} + +int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info) +{ +	int ret = 0; +	char *pkgpath = NULL; + +	ALPM_LOG_FUNC; + +	if(db == NULL || info == NULL) { +		RET_ERR(PM_ERR_DB_NULL, -1); +	} + +	pkgpath = get_pkgpath(db, info); + +	ret = _alpm_rmrf(pkgpath); +	free(pkgpath); +	if(ret != 0) { +		ret = -1; +	} +	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..c272bd47 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -1,7 +1,7 @@  /*   *  be_package.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -24,8 +24,8 @@  #include <stdlib.h>  #include <string.h>  #include <limits.h> -#include <ctype.h>  #include <locale.h> /* setlocale */ +#include <errno.h>  /* libarchive */  #include <archive.h> @@ -39,6 +39,109 @@  #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 + */ +static 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 + */ +static 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); +	} +} + +/* +static 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 + */ +static 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. + */ +static struct pkg_operations *get_file_pkg_ops(void) +{ +	static struct pkg_operations file_pkg_ops; +	static int file_pkg_ops_initialized = 0; +	if(!file_pkg_ops_initialized) { +		file_pkg_ops = default_pkg_ops; +		file_pkg_ops.changelog_open  = _package_changelog_open; +		file_pkg_ops.changelog_read  = _package_changelog_read; +		file_pkg_ops.changelog_close = _package_changelog_close; +		file_pkg_ops_initialized = 1; +	} +	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 @@ -47,17 +150,22 @@   */  static int parse_descfile(struct archive *a, pmpkg_t *newpkg)  { -	char line[PATH_MAX];  	char *ptr = NULL;  	char *key = NULL;  	int linenum = 0; +	struct archive_read_buffer buf;  	ALPM_LOG_FUNC; -	/* loop until we reach EOF (where archive_fgets will return NULL) */ -	while(_alpm_archive_fgets(line, PATH_MAX, a) != NULL) { +	memset(&buf, 0, sizeof(buf)); +	/* 512K for a line length seems reasonable */ +	buf.max_line_size = 512 * 1024; + +	/* loop until we reach EOF or other error */ +	while(_alpm_archive_fgets(a, &buf) == ARCHIVE_OK) { +		char *line = _alpm_strtrim(buf.line); +  		linenum++; -		_alpm_strtrim(line);  		if(strlen(line) == 0 || line[0] == '#') {  			continue;  		} @@ -69,52 +177,42 @@ 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, "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")) { -				char first = tolower((unsigned char)ptr[0]); -				if(first > 'a' && first < 'z') { -					struct tm tmp_tm = {0}; /* initialize to null in case of failure */ -					setlocale(LC_TIME, "C"); -					strptime(ptr, "%a %b %e %H:%M:%S %Y", &tmp_tm); -					newpkg->builddate = mktime(&tmp_tm); -					setlocale(LC_TIME, ""); -				} else { -					newpkg->builddate = atol(ptr); -				} -			} else if(!strcmp(key, "packager")) { +			} else if(strcmp(key, "builddate") == 0) { +				newpkg->builddate = _alpm_parsedate(ptr); +			} 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", @@ -174,6 +272,8 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)  	newpkg->filename = strdup(pkgfile);  	newpkg->size = st.st_size; +	_alpm_log(PM_LOG_DEBUG, "starting package load for %s\n", pkgfile); +  	/* If full is false, only read through the archive until we find our needed  	 * metadata. If it is true, read through the entire archive, which serves  	 * as a verfication of integrity and allows us to create the filelist. */ @@ -232,11 +332,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 +349,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..4676e8a6 --- /dev/null +++ b/lib/libalpm/be_sync.c @@ -0,0 +1,404 @@ +/* + *  be_sync.c + * + *  Copyright (c) 2006-2011 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 <locale.h> +#include <limits.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, pmpkg_t *likely_pkg); + +static int sync_db_populate(pmdb_t *db) +{ +	int count = 0; +	struct archive *archive; +	struct archive_entry *entry; +	pmpkg_t *pkg = NULL; + +	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; + +		st = archive_entry_stat(entry); + +		if(S_ISDIR(st->st_mode)) { +			const char *name; + +			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, pkg); +		} +	} + +	db->pkgcache = alpm_list_msort(db->pkgcache, (size_t)count, _alpm_pkg_cmp); +	archive_read_finish(archive); + +	return(count); +} + +#define READ_NEXT(s) do { \ +	if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ +	s = _alpm_strtrim(buf.line); \ +} while(0) + +#define READ_AND_STORE(f) do { \ +	READ_NEXT(line); \ +	STRDUP(f, line, goto error); \ +} while(0) + +#define READ_AND_STORE_ALL(f) do { \ +	char *linedup; \ +	READ_NEXT(line); \ +	if(strlen(line) == 0) break; \ +	STRDUP(linedup, line, goto error); \ +	f = alpm_list_add(f, linedup); \ +} while(1) /* note the while(1) and not (0) */ + +static int sync_db_read(pmdb_t *db, struct archive *archive, +		struct archive_entry *entry, pmpkg_t *likely_pkg) +{ +	const char *entryname = NULL, *filename; +	char *pkgname, *p, *q; +	pmpkg_t *pkg; +	struct archive_read_buffer buf; + +	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); + +	memset(&buf, 0, sizeof(buf)); +	/* 512K for a line length seems reasonable */ +	buf.max_line_size = 512 * 1024; + +	/* 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--); +	filename = q + 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 */ +	if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) { +		pkg = likely_pkg; +	} else { +		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(archive, &buf) == ARCHIVE_OK) { +			char *line = _alpm_strtrim(buf.line); + +			if(strcmp(line, "%NAME%") == 0) { +				READ_NEXT(line); +				if(strcmp(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) { +				READ_NEXT(line); +				if(strcmp(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) { +				READ_AND_STORE(pkg->filename); +			} else if(strcmp(line, "%DESC%") == 0) { +				READ_AND_STORE(pkg->desc); +			} else if(strcmp(line, "%GROUPS%") == 0) { +				READ_AND_STORE_ALL(pkg->groups); +			} else if(strcmp(line, "%URL%") == 0) { +				READ_AND_STORE(pkg->url); +			} else if(strcmp(line, "%LICENSE%") == 0) { +				READ_AND_STORE_ALL(pkg->licenses); +			} else if(strcmp(line, "%ARCH%") == 0) { +				READ_AND_STORE(pkg->arch); +			} else if(strcmp(line, "%BUILDDATE%") == 0) { +				READ_NEXT(line); +				pkg->builddate = _alpm_parsedate(line); +			} else if(strcmp(line, "%PACKAGER%") == 0) { +				READ_AND_STORE(pkg->packager); +			} 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. +				 */ +				READ_NEXT(line); +				pkg->size = atol(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) { +				READ_NEXT(line); +				pkg->isize = atol(line); +			} else if(strcmp(line, "%MD5SUM%") == 0) { +				READ_AND_STORE(pkg->md5sum); +			} else if(strcmp(line, "%REPLACES%") == 0) { +				READ_AND_STORE_ALL(pkg->replaces); +			} else if(strcmp(line, "%DEPENDS%") == 0) { +				/* Different than the rest because of the _alpm_splitdep call. */ +				while(1) { +					READ_NEXT(line); +					if(strlen(line) == 0) break; +					pkg->depends = alpm_list_add(pkg->depends, _alpm_splitdep(line)); +				} +			} else if(strcmp(line, "%OPTDEPENDS%") == 0) { +				READ_AND_STORE_ALL(pkg->optdepends); +			} else if(strcmp(line, "%CONFLICTS%") == 0) { +				READ_AND_STORE_ALL(pkg->conflicts); +			} else if(strcmp(line, "%PROVIDES%") == 0) { +				READ_AND_STORE_ALL(pkg->provides); +			} else if(strcmp(line, "%DELTAS%") == 0) { +				READ_AND_STORE_ALL(pkg->deltas); +			} +		} +	} else { +		 /* unknown database file */ +		_alpm_log(PM_LOG_DEBUG, "unknown database file: %s", filename); +	} + +error: +	FREE(pkgname); +	/* 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..fc25e7d3 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -1,7 +1,7 @@  /*   *  conflict.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org> @@ -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)); @@ -403,8 +402,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,  		alpm_list_t *upgrade, alpm_list_t *remove)  {  	alpm_list_t *i, *j, *conflicts = NULL; -	int numtargs = alpm_list_count(upgrade); -	int current; +	size_t numtargs = alpm_list_count(upgrade); +	size_t current;  	ALPM_LOG_FUNC; @@ -426,8 +425,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,  			continue;  		} -		double percent = (double)current / numtargs; -		PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", (percent * 100), +		int percent = (current * 100) / numtargs; +		PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", percent,  		         numtargs, current);  		/* CHECK 1: check every target against every target */  		_alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s\n", diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h index e60e5b3b..09b4f99b 100644 --- a/lib/libalpm/conflict.h +++ b/lib/libalpm/conflict.h @@ -1,7 +1,7 @@  /*   *  conflict.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index c8a91a2b..bf9a70d4 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -1,7 +1,7 @@  /*   *  db.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -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);  } @@ -168,7 +172,7 @@ int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url)  	alpm_list_t *i;  	int found = 0;  	char *newurl; -	int len = 0; +	size_t len = 0;  	ALPM_LOG_FUNC; @@ -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..b7fa7ca6 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -1,7 +1,7 @@  /*   *  db.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -23,22 +23,28 @@  #define _ALPM_DB_H  #include "alpm.h" -#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 +52,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 +69,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.c b/lib/libalpm/delta.c index 72835005..10c982f2 100644 --- a/lib/libalpm/delta.c +++ b/lib/libalpm/delta.c @@ -1,7 +1,7 @@  /*   *  delta.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2007-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h index 76283380..d7a81c47 100644 --- a/lib/libalpm/delta.h +++ b/lib/libalpm/delta.h @@ -1,7 +1,7 @@  /*   *  delta.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2007-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -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..a7203b4b 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -1,7 +1,7 @@  /*   *  deps.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -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,35 +319,43 @@ 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; - -	ALPM_LOG_FUNC; - -	const char *pkgname = alpm_pkg_get_name(pkg); -	const char *pkgversion = alpm_pkg_get_version(pkg);  	int satisfy = 0;  	/* check (pkg->name, pkg->version) */ -	satisfy = (strcmp(pkgname, dep->name) == 0 -			&& dep_vercmp(pkgversion, dep->mod, dep->version)); +	if(pkg->name_hash && dep->name_hash +			&& pkg->name_hash != dep->name_hash) { +		/* skip more expensive checks */ +	} else { +		satisfy = (strcmp(pkg->name, dep->name) == 0 +				&& dep_vercmp(pkg->version, dep->mod, dep->version)); +		if(satisfy) { +			return(satisfy); +		} +	}  	/* check provisions, format : "name=version" */  	for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) { -		char *provname = strdup(i->data); -		char *provver = strchr(provname, '='); +		const char *provision = i->data; +		const char *provver = strchr(provision, '=');  		if(provver == NULL) { /* no provision version */  			satisfy = (dep->mod == PM_DEP_MOD_ANY -					&& strcmp(provname, dep->name) == 0); +					&& strcmp(provision, dep->name) == 0);  		} else { -			*provver = '\0'; +			/* This is a bit tricker than the old code for performance reasons. To +			 * prevent the need to copy and duplicate strings, strncmp only the name +			 * portion if they are the same length, since there is a version and +			 * operator in play here. Cast is to silence sign conversion warning; +			 * we know provver >= provision if we are here. */ +			size_t namelen = (size_t)(provver - provision);  			provver += 1; -			satisfy = (strcmp(provname, dep->name) == 0 +			satisfy = (strlen(dep->name) == namelen +					&& strncmp(provision, dep->name, namelen) == 0  					&& dep_vercmp(provver, dep->mod, dep->version));  		} -		free(provname);  	}  	return(satisfy); @@ -368,52 +364,44 @@ int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)  pmdepend_t *_alpm_splitdep(const char *depstring)  {  	pmdepend_t *depend; -	char *ptr = NULL; -	char *newstr = NULL; +	const char *ptr, *version = NULL;  	if(depstring == NULL) {  		return(NULL);  	} -	STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL));  	CALLOC(depend, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));  	/* Find a version comparator if one exists. If it does, set the type and  	 * increment the ptr accordingly so we can copy the right strings. */ -	if((ptr = strstr(newstr, ">="))) { +	if((ptr = strstr(depstring, ">="))) {  		depend->mod = PM_DEP_MOD_GE; -		*ptr = '\0'; -		ptr += 2; -	} else if((ptr = strstr(newstr, "<="))) { +		version = ptr + 2; +	} else if((ptr = strstr(depstring, "<="))) {  		depend->mod = PM_DEP_MOD_LE; -		*ptr = '\0'; -		ptr += 2; -	} else if((ptr = strstr(newstr, "="))) { /* Note: we must do =,<,> checks after <=, >= checks */ +		version = ptr + 2; +	} else if((ptr = strstr(depstring, "="))) { +		/* Note: we must do =,<,> checks after <=, >= checks */  		depend->mod = PM_DEP_MOD_EQ; -		*ptr = '\0'; -		ptr += 1; -	} else if((ptr = strstr(newstr, "<"))) { +		version = ptr + 1; +	} else if((ptr = strstr(depstring, "<"))) {  		depend->mod = PM_DEP_MOD_LT; -		*ptr = '\0'; -		ptr += 1; -	} else if((ptr = strstr(newstr, ">"))) { +		version = ptr + 1; +	} else if((ptr = strstr(depstring, ">"))) {  		depend->mod = PM_DEP_MOD_GT; -		*ptr = '\0'; -		ptr += 1; +		version = ptr + 1;  	} else { -		/* no version specified - copy the name and return it */ +		/* no version specified, leave version and ptr NULL */  		depend->mod = PM_DEP_MOD_ANY; -		STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL)); -		depend->version = NULL; -		free(newstr); -		return(depend);  	} -	/* if we get here, we have a version comparator, copy the right parts -	 * to the right places */ -	STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL)); -	STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL)); -	free(newstr); +	/* copy the right parts to the right places */ +	STRNDUP(depend->name, depstring, ptr - depstring, +			RET_ERR(PM_ERR_MEMORY, NULL)); +	depend->name_hash = _alpm_hash_sdbm(depend->name); +	if(version) { +		STRDUP(depend->version, version, RET_ERR(PM_ERR_MEMORY, NULL)); +	}  	return(depend);  } @@ -424,6 +412,7 @@ pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep)  	CALLOC(newdep, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));  	STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL)); +	newdep->name_hash = dep->name_hash;  	STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL));  	newdep->mod = dep->mod; @@ -525,7 +514,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 +535,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 +661,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..bd5e9a4c 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -1,7 +1,7 @@  /*   *  deps.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -29,9 +29,10 @@  /* Dependency */  struct __pmdepend_t { -	pmdepmod_t mod;  	char *name;  	char *version; +	unsigned long name_hash; +	pmdepmod_t mod;  };  /* Missing dependency */ @@ -55,6 +56,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..dfafdac0 --- /dev/null +++ b/lib/libalpm/diskspace.c @@ -0,0 +1,337 @@ +/* + *  diskspace.c + * + *  Copyright (c) 2010-2011 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 + +/* 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 = 0l; +		mp->max_blocks_needed = 0l; +		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 = 0l; +		mp->max_blocks_needed = 0l; +		mp->used = 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; +		/* the addition of (divisor - 1) performs ceil() with integer division */ +		data->blocks_needed -= +			(st.st_size + data->fsp.f_bsize - 1l) / data->fsp.f_bsize; +	} + +	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; +		/* the addition of (divisor - 1) performs ceil() with integer division */ +		data->blocks_needed += +			(archive_entry_size(entry) + data->fsp.f_bsize - 1l) / data->fsp.f_bsize; +		data->used = 1; + +		if(archive_read_data_skip(archive)) { +			_alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"), +					pkg->name, archive_error_string(archive)); +			pm_errno = PM_ERR_LIBARCHIVE; +			break; +		} +	} + +	archive_read_finish(archive); + +cleanup: +	return(ret); +} + +int _alpm_check_diskspace(pmtrans_t *trans, pmdb_t *db_local) +{ +	alpm_list_t *mount_points, *i; +	size_t replaces = 0, current = 0, numtargs; +	int abort = 0; +	alpm_list_t *targ; + +	numtargs = alpm_list_count(trans->add); +	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++) { +			pmpkg_t *local_pkg; +			int percent = (current * 100) / numtargs; +			PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", percent, +					numtargs, current); + +			local_pkg = targ->data; +			calculate_removed_size(mount_points, local_pkg); +		} +	} + +	for(targ = trans->add; targ; targ = targ->next, current++) { +		pmpkg_t *pkg, *local_pkg; +		int percent = (current * 100) / numtargs; +		PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", percent, +				numtargs, current); + +		pkg = targ->data; +		/* is this package already installed? */ +		local_pkg = _alpm_db_get_pkgfromcache(db_local, pkg->name); +		if(local_pkg) { +			calculate_removed_size(mount_points, local_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 = ((long)data->fsp.f_blocks / 20) + 1; +			long twentymb = (20 * 1024 * 1024 / (long)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 >= 0 && +			   (unsigned long)(data->max_blocks_needed + cushion) > data->fsp.f_bfree) { +				_alpm_log(PM_LOG_ERROR, _("Partition %s too full: %ld blocks needed, %ld blocks free)\n"), +						data->mount_dir, data->max_blocks_needed + cushion, +						(unsigned long)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..25b9cfbf --- /dev/null +++ b/lib/libalpm/diskspace.h @@ -0,0 +1,46 @@ +/* + *  diskspace.h + * + *  Copyright (c) 2010-2011 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..cb6d000c 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -1,7 +1,7 @@  /*   *  download.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -29,16 +29,13 @@  #include <sys/types.h>  #include <sys/stat.h>  #include <signal.h> -#include <limits.h> -/* the following two are needed on BSD for libfetch */ -#if defined(HAVE_SYS_SYSLIMITS_H) -#include <sys/syslimits.h> /* PATH_MAX */ -#endif +/* the following two are needed for FreeBSD's libfetch */ +#include <limits.h> /* PATH_MAX */  #if defined(HAVE_SYS_PARAM_H)  #include <sys/param.h> /* MAXHOSTNAMELEN */  #endif -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  #include <fetch.h>  #endif @@ -58,7 +55,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 +86,7 @@ static const char *gethost(struct url *fileurl)  }  int dload_interrupted; -static RETSIGTYPE inthandler(int signum) +static void inthandler(int signum)  {  	dload_interrupted = 1;  } @@ -250,8 +247,8 @@ static int download_internal(const char *url, const char *localpath,  	while((nread = fetchIO_read(dlf, buffer, PM_DLBUF_LEN)) > 0) {  		check_stop();  		size_t nwritten = 0; -		nwritten = fwrite(buffer, 1, nread, localf); -		if((nwritten != nread) || ferror(localf)) { +		nwritten = fwrite(buffer, 1, (size_t)nread, 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 +335,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/dload.h b/lib/libalpm/dload.h index e60174e4..63266491 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -1,7 +1,7 @@  /*   *  dload.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 8d8d0458..1b144a5a 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -1,7 +1,7 @@  /*   *  error.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -22,16 +22,13 @@  /* TODO: needed for the libfetch stuff, unfortunately- we should kill it */  #include <stdio.h> -#include <limits.h> -/* the following two are needed on BSD for libfetch */ -#if defined(HAVE_SYS_SYSLIMITS_H) -#include <sys/syslimits.h> /* PATH_MAX */ -#endif +/* the following two are needed for FreeBSD's libfetch */ +#include <limits.h> /* PATH_MAX */  #if defined(HAVE_SYS_PARAM_H)  #include <sys/param.h> /* MAXHOSTNAMELEN */  #endif -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH  #include <fetch.h> /* fetchLastErrString */  #endif @@ -60,6 +57,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 free disk space");  		/* Interface */  		case PM_ERR_HANDLE_NULL:  			return _("library not initialized"); @@ -145,7 +144,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/graph.h b/lib/libalpm/graph.h index c82e6811..69f65000 100644 --- a/lib/libalpm/graph.h +++ b/lib/libalpm/graph.h @@ -1,7 +1,7 @@  /*   *  graph.h - helpful graph structure and setup/teardown methods   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/group.c b/lib/libalpm/group.c index 061bb0e4..398c2588 100644 --- a/lib/libalpm/group.c +++ b/lib/libalpm/group.c @@ -1,7 +1,7 @@  /*   *  group.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/group.h b/lib/libalpm/group.h index 5d8cf775..c92684e3 100644 --- a/lib/libalpm/group.h +++ b/lib/libalpm/group.h @@ -1,7 +1,7 @@  /*   *  group.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index aa34cf45..8872ed0a 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -1,7 +1,7 @@  /*   *  handle.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -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..fa29d112 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -1,7 +1,7 @@  /*   *  handle.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -60,12 +60,13 @@ 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 */  extern pmhandle_t *handle; -pmhandle_t *_alpm_handle_new(); +pmhandle_t *_alpm_handle_new(void);  void _alpm_handle_free(pmhandle_t *handle);  #endif /* _ALPM_HANDLE_H */ diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c index 86bb8257..dc4f938a 100644 --- a/lib/libalpm/log.c +++ b/lib/libalpm/log.c @@ -1,7 +1,7 @@  /*   *  log.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/log.h b/lib/libalpm/log.h index d358733f..5ce08e45 100644 --- a/lib/libalpm/log.h +++ b/lib/libalpm/log.h @@ -1,7 +1,7 @@  /*   *  log.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 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..d4b3b9c0 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -1,7 +1,7 @@  /*   *  package.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu> @@ -25,24 +25,18 @@  #include <stdio.h>  #include <stdlib.h> -#include <limits.h>  #include <string.h>  #include <ctype.h>  #include <errno.h>  #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 +57,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 +77,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 +93,189 @@ 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. */ +static const char *_pkg_get_filename(pmpkg_t *pkg)    { return pkg->filename; } +static const char *_pkg_get_name(pmpkg_t *pkg)        { return pkg->name; } +static const char *_pkg_get_version(pmpkg_t *pkg)     { return pkg->version; } +static const char *_pkg_get_desc(pmpkg_t *pkg)        { return pkg->desc; } +static const char *_pkg_get_url(pmpkg_t *pkg)         { return pkg->url; } +static time_t _pkg_get_builddate(pmpkg_t *pkg)        { return pkg->builddate; } +static time_t _pkg_get_installdate(pmpkg_t *pkg)      { return pkg->installdate; } +static const char *_pkg_get_packager(pmpkg_t *pkg)    { return pkg->packager; } +static const char *_pkg_get_md5sum(pmpkg_t *pkg)      { return pkg->md5sum; } +static const char *_pkg_get_arch(pmpkg_t *pkg)        { return pkg->arch; } +static off_t _pkg_get_size(pmpkg_t *pkg)              { return pkg->size; } +static off_t _pkg_get_isize(pmpkg_t *pkg)             { return pkg->isize; } +static pmpkgreason_t _pkg_get_reason(pmpkg_t *pkg)    { return pkg->reason; } +static int _pkg_has_scriptlet(pmpkg_t *pkg)           { return pkg->scriptlet; } + +static alpm_list_t *_pkg_get_licenses(pmpkg_t *pkg)   { return pkg->licenses; } +static alpm_list_t *_pkg_get_groups(pmpkg_t *pkg)     { return pkg->groups; } +static alpm_list_t *_pkg_get_depends(pmpkg_t *pkg)    { return pkg->depends; } +static alpm_list_t *_pkg_get_optdepends(pmpkg_t *pkg) { return pkg->optdepends; } +static alpm_list_t *_pkg_get_conflicts(pmpkg_t *pkg)  { return pkg->conflicts; } +static alpm_list_t *_pkg_get_provides(pmpkg_t *pkg)   { return pkg->provides; } +static alpm_list_t *_pkg_get_replaces(pmpkg_t *pkg)   { return pkg->replaces; } +static alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg)     { return pkg->deltas; } +static alpm_list_t *_pkg_get_files(pmpkg_t *pkg)      { return pkg->files; } +static 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, +	.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)); - -	if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) { -		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); -	} -	return pkg->reason; +	return pkg->ops->get_reason(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 +289,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 +327,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 +406,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 +420,6 @@ 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->reason = pkg->reason;  	newpkg->licenses   = alpm_list_strdup(pkg->licenses); @@ -657,6 +437,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 +507,13 @@ 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; -  	ALPM_LOG_FUNC; -	cmp = alpm_pkg_vercmp(alpm_pkg_get_version(spkg), +	return alpm_pkg_vercmp(alpm_pkg_get_version(spkg),  			alpm_pkg_get_version(localpkg)); - -	if(cmp < 0 && alpm_pkg_has_force(spkg)) { -		cmp = 1; -	} - -	return(cmp);  }  /* Helper function for comparing packages @@ -749,7 +522,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 +531,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 +539,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..b161d5f1 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -1,7 +1,7 @@  /*   *  package.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org> @@ -31,27 +31,92 @@  #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 (*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; +  	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 +129,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..5fba0b07 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -1,7 +1,7 @@  /*   *  remove.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -42,12 +42,11 @@  #include "backup.h"  #include "package.h"  #include "db.h" -#include "cache.h"  #include "deps.h"  #include "handle.h"  #include "alpm.h" -int SYMEXPORT alpm_remove_target(char *target) +int SYMEXPORT alpm_remove_target(const char *target)  {  	pmpkg_t *info;  	pmtrans_t *trans; @@ -299,10 +298,12 @@ static void unlink_file(pmpkg_t *info, char *filename, alpm_list_t *skip_remove,  	}  } -int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *trans) +int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, +		pmtrans_t *trans)  {  	alpm_list_t *skip_remove, *b;  	alpm_list_t *newfiles, *lp; +	size_t filenum;  	alpm_list_t *files = alpm_pkg_get_files(oldpkg);  	const char *pkgname = alpm_pkg_get_name(oldpkg); @@ -311,9 +312,14 @@ 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)); +	skip_remove = alpm_list_join( +			alpm_list_strdup(trans->skip_remove), +			alpm_list_strdup(handle->noupgrade));  	/* Add files in the NEW backup array to the skip_remove array  	 * so this removal operation doesn't kill them */  	/* old package backup list */ @@ -337,6 +343,9 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra  		}  	} +	filenum = alpm_list_count(files); +	_alpm_log(PM_LOG_DEBUG, "removing %ld files\n", (unsigned long)filenum); +  	/* iterate through the list backwards, unlinking files */  	newfiles = alpm_list_reverse(files);  	for(lp = newfiles; lp; lp = alpm_list_next(lp)) { @@ -345,10 +354,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));  	} @@ -365,7 +375,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)  {  	pmpkg_t *info;  	alpm_list_t *targ, *lp; -	int pkg_count; +	size_t pkg_count;  	ALPM_LOG_FUNC; @@ -379,7 +389,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)  		char scriptlet[PATH_MAX];  		info = (pmpkg_t*)targ->data;  		const char *pkgname = NULL; -		int targcount = alpm_list_count(targ); +		size_t targcount = alpm_list_count(targ);  		if(handle->trans->state == STATE_INTERRUPTED) {  			return(0); @@ -402,6 +412,9 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)  		if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {  			alpm_list_t *files = alpm_pkg_get_files(info); +			alpm_list_t *newfiles; +			size_t filenum; +  			for(lp = files; lp; lp = lp->next) {  				if(!can_remove_file(lp->data, NULL)) {  					_alpm_log(PM_LOG_DEBUG, "not removing package '%s', can't remove all files\n", @@ -410,9 +423,8 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)  				}  			} -			int filenum = alpm_list_count(files); -			alpm_list_t *newfiles; -			_alpm_log(PM_LOG_DEBUG, "removing %d files\n", filenum); +			filenum = alpm_list_count(files); +			_alpm_log(PM_LOG_DEBUG, "removing %ld files\n", (unsigned long)filenum);  			/* init progress bar */  			PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name, 0, @@ -421,14 +433,13 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)  			/* iterate through the list backwards, unlinking files */  			newfiles = alpm_list_reverse(files);  			for(lp = newfiles; lp; lp = alpm_list_next(lp)) { -				double percent; +				int percent;  				unlink_file(info, lp->data, NULL, trans->flags & PM_TRANS_FLAG_NOSAVE);  				/* update progress bar after each file */ -				percent = (double)position / (double)filenum; +				percent = (position * 100) / filenum;  				PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name, -						(double)(percent * 100), pkg_count, -						(pkg_count - targcount + 1)); +						percent, pkg_count, (pkg_count - targcount + 1));  				position++;  			}  			alpm_list_free(newfiles); @@ -447,7 +458,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/remove.h b/lib/libalpm/remove.h index 55858909..a67e37a1 100644 --- a/lib/libalpm/remove.h +++ b/lib/libalpm/remove.h @@ -1,7 +1,7 @@  /*   *  remove.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 4cbaf0cb..dbd15065 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -1,7 +1,7 @@  /*   *  sync.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -31,7 +31,7 @@  #include <stdint.h> /* intmax_t */  #include <unistd.h>  #include <time.h> -#include <dirent.h> +#include <limits.h>  /* libalpm */  #include "sync.h" @@ -39,7 +39,6 @@  #include "log.h"  #include "package.h"  #include "db.h" -#include "cache.h"  #include "deps.h"  #include "conflict.h"  #include "trans.h" @@ -50,6 +49,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) @@ -329,7 +329,7 @@ static int sync_target(alpm_list_t *dbs_sync, const char *target)   * @param target the name of the sync target to add   * @return 0 on success, -1 on error (pm_errno is set accordingly)   */ -int SYMEXPORT alpm_sync_dbtarget(char *dbname, char *target) +int SYMEXPORT alpm_sync_dbtarget(const char *dbname, const char *target)  {  	alpm_list_t *i;  	alpm_list_t *dbs_sync; @@ -362,7 +362,7 @@ int SYMEXPORT alpm_sync_dbtarget(char *dbname, char *target)   * @param target the name of the sync target to add   * @return 0 on success, -1 on error (pm_errno is set accordingly)   */ -int SYMEXPORT alpm_sync_target(char *target) +int SYMEXPORT alpm_sync_target(const char *target)  {  	alpm_list_t *dbs_sync; @@ -549,10 +549,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 { @@ -822,7 +822,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)  {  	alpm_list_t *i, *j, *files = NULL;  	alpm_list_t *deltas = NULL; -	int replaces = 0; +	size_t numtargs, current = 0, replaces = 0;  	int errors = 0;  	const char *cachedir = NULL;  	int ret = -1; @@ -854,7 +854,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); @@ -949,14 +949,18 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)  	}  	/* Check integrity of packages */ +	numtargs = alpm_list_count(trans->add);  	EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL);  	errors = 0; -	for(i = trans->add; i; i = i->next) { +	for(i = trans->add; i; i = i->next, current++) {  		pmpkg_t *spkg = i->data; +		int percent = (current * 100) / numtargs;  		if(spkg->origin == PKG_FROM_FILE) {  			continue; /* pkg_load() has been already called, this package is valid */  		} +		PROGRESS(trans, PM_TRANS_PROGRESS_INTEGRITY_START, "", percent, +				numtargs, current);  		const char *filename = alpm_pkg_get_filename(spkg);  		const char *md5sum = alpm_pkg_get_md5sum(spkg); @@ -983,11 +987,14 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)  		i->data = pkgfile;  		_alpm_pkg_free_trans(spkg); /* spkg has been removed from the target list */  	} +	PROGRESS(trans, PM_TRANS_PROGRESS_INTEGRITY_START, "", 100, +			numtargs, current); +	EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL);  	if(errors) {  		pm_errno = PM_ERR_PKG_INVALID;  		goto error;  	} -	EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL); +  	if(trans->flags & PM_TRANS_FLAG_DOWNLOADONLY) {  		ret = 0;  		goto error; @@ -1018,6 +1025,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/sync.h b/lib/libalpm/sync.h index 000a09cc..90a2d40d 100644 --- a/lib/libalpm/sync.h +++ b/lib/libalpm/sync.h @@ -1,7 +1,7 @@  /*   *  sync.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index 02612ec1..804ab7a1 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -1,7 +1,7 @@  /*   *  trans.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -31,6 +31,7 @@  #include <sys/stat.h>  #include <sys/statvfs.h>  #include <errno.h> +#include <limits.h>  /* libalpm */  #include "trans.h" @@ -44,7 +45,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 +323,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 +344,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 +372,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 +402,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/trans.h b/lib/libalpm/trans.h index 51136423..ce2dc529 100644 --- a/lib/libalpm/trans.h +++ b/lib/libalpm/trans.h @@ -1,7 +1,7 @@  /*   *  trans.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 32eaa442..089b37cb 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -1,7 +1,7 @@  /*   *  util.c   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -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);  		}  	} @@ -635,7 +668,7 @@ int _alpm_lstat(const char *path, struct stat *buf)  {  	int ret;  	char *newpath = strdup(path); -	int len = strlen(newpath); +	size_t len = strlen(newpath);  	/* strip the trailing slash if one exists */  	if(len != 0 && newpath[len - 1] == '/') { @@ -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) { @@ -701,33 +771,191 @@ int _alpm_test_md5sum(const char *filepath, const char *md5sum)  	return(ret);  } -char *_alpm_archive_fgets(char *line, size_t size, struct archive *a) +/* Note: does NOT handle sparse files on purpose for speed. */ +int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)  { -	/* for now, just read one char at a time until we get to a -	 * '\n' char. we can optimize this later with an internal -	 * buffer. */ -	/* leave room for zero terminator */ -	char *last = line + size - 1; -	char *i; - -	for(i = line; i < last; i++) { -		int ret = archive_read_data(a, i, 1); -		/* special check for first read- if null, return null, -		 * this indicates EOF */ -		if(i == line && (ret <= 0 || *i == '\0')) { -			return(NULL); +	char *i = NULL; +	int64_t offset; +	int done = 0; + +	while(1) { +		/* have we processed this entire block? */ +		if(b->block + b->block_size == b->block_offset) { +			if(b->ret == ARCHIVE_EOF) { +				/* reached end of archive on the last read, now we are out of data */ +				goto cleanup; +			} + +			/* zero-copy - this is the entire next block of data. */ +			b->ret = archive_read_data_block(a, (void*)&b->block, +					&b->block_size, &offset); +			b->block_offset = b->block; + +			/* error or end of archive with no data read, cleanup */ +			if(b->ret < ARCHIVE_OK || +					(b->block_size == 0 && b->ret == ARCHIVE_EOF)) { +				goto cleanup; +			}  		} -		/* check if read value was null or newline */ -		if(ret <= 0 || *i == '\0' || *i == '\n') { -			last = i + 1; -			break; + +		/* loop through the block looking for EOL characters */ +		for(i = b->block_offset; i < (b->block + b->block_size); i++) { +			/* check if read value was null or newline */ +			if(*i == '\0' || *i == '\n') { +				done = 1; +				break; +			}  		} + +		/* allocate our buffer, or ensure our existing one is big enough */ +		if(!b->line) { +			/* set the initial buffer to the read block_size */ +			CALLOC(b->line, b->block_size + 1, sizeof(char), +					RET_ERR(PM_ERR_MEMORY, -1)); +			b->line_size = b->block_size + 1; +			b->line_offset = b->line; +		} else { +			size_t needed = (size_t)((b->line_offset - b->line) +					+ (i - b->block_offset) + 1); +			if(needed > b->max_line_size) { +				RET_ERR(PM_ERR_MEMORY, -1); +			} +			if(needed > b->line_size) { +				/* need to realloc + copy data to fit total length */ +				char *new; +				CALLOC(new, needed, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1)); +				memcpy(new, b->line, b->line_size); +				b->line_size = needed; +				b->line_offset = new + (b->line_offset - b->line); +				free(b->line); +				b->line = new; +			} +		} + +		if(done) { +			size_t len = (size_t)(i - b->block_offset); +			memcpy(b->line_offset, b->block_offset, len); +			b->line_offset[len] = '\0'; +			b->block_offset = ++i; +			/* this is the main return point; from here you can read b->line */ +			return(ARCHIVE_OK); +		} else { +			/* we've looked through the whole block but no newline, copy it */ +			size_t len = (size_t)(b->block + b->block_size - b->block_offset); +			memcpy(b->line_offset, b->block_offset, len); +			b->line_offset += len; +			b->block_offset = i; +		} +	} + +cleanup: +	{ +		int ret = b->ret; +		FREE(b->line); +		memset(b, 0, sizeof(b)); +		return(ret);  	} +} -	/* always null terminate the buffer */ -	*last = '\0'; +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. +	 */ +	const char *version, *end; + +	if(target == NULL || pkg == NULL) { +		return(-1); +	} +	end = target + strlen(target); -	return(line); +	/* remove any trailing '/' */ +	while (*(end - 1) == '/') { +	  --end; +	} + +	/* do the magic parsing- find the beginning of the version string +	 * by doing two iterations of same loop to lop off two hyphens */ +	for(version = end - 1; *version && *version != '-'; version--); +	for(version = version - 1; *version && *version != '-'; version--); +	if(*version != '-' || version == target) { +		return(-1); +	} + +	/* copy into fields and return */ +	if(pkg->version) { +		FREE(pkg->version); +	} +	/* version actually points to the dash, so need to increment 1 and account +	 * for potential end character */ +	STRNDUP(pkg->version, version + 1, end - version - 1, +			RET_ERR(PM_ERR_MEMORY, -1)); + +	if(pkg->name) { +		FREE(pkg->name); +	} +	STRNDUP(pkg->name, target, version - target, RET_ERR(PM_ERR_MEMORY, -1)); +	pkg->name_hash = _alpm_hash_sdbm(pkg->name); + +	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);  } +long _alpm_parsedate(const char *line) +{ +	if(isalpha((unsigned char)line[0])) { +		/* initialize to null in case of failure */ +		struct tm tmp_tm = { 0 }; +		setlocale(LC_TIME, "C"); +		strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); +		setlocale(LC_TIME, ""); +		return(mktime(&tmp_tm)); +	} +	return(atol(line)); +} + +#ifndef HAVE_STRNDUP +/* A quick and dirty implementation derived from glibc */ +static size_t strnlen(const char *s, size_t max) +{ +    register const char *p; +    for(p = s; *p && max--; ++p); +    return(p - s); +} + +char *strndup(const char *s, size_t n) +{ +  size_t len = strnlen(s, n); +  char *new = (char *) malloc(len + 1); + +  if (new == NULL) +    return NULL; + +  new[len] = '\0'; +  return (char *) memcpy(new, s, len); +} +#endif +  /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 8a3154a7..015e9bf5 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -1,7 +1,7 @@  /*   *  util.h   * - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>   *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>   *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>   *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -27,6 +27,7 @@  #include "config.h"  #include "alpm_list.h" +#include "package.h" /* pmpkg_t */  #include <stdio.h>  #include <string.h> @@ -49,6 +50,7 @@  #define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0)  /* This strdup macro is NULL safe- copying NULL will yield NULL */  #define STRDUP(r, s, action) do { if(s != NULL) { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) +#define STRNDUP(r, s, l, action) do { if(s != NULL) { r = strndup(s, l); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0)  #define FREE(p) do { free(p); p = NULL; } while(0) @@ -58,36 +60,56 @@  	_alpm_log(PM_LOG_DEBUG, "returning error %d from %s : %s\n", err, __func__, alpm_strerrorlast()); \  	return(ret); } while(0) +/** + * Used as a buffer/state holder for _alpm_archive_fgets(). + */ +struct archive_read_buffer { +	char *line; +	char *line_offset; +	size_t line_size; +	size_t max_line_size; + +	char *block; +	char *block_offset; +	size_t block_size; + +	int ret; +}; +  int _alpm_makepath(const char *path);  int _alpm_makepath_mode(const char *path, mode_t mode);  int _alpm_copyfile(const char *src, const char *dest);  char *_alpm_strtrim(char *str); -int _alpm_lckmk(); -int _alpm_lckrm(); +int _alpm_lckmk(void); +int _alpm_lckrm(void);  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);  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_archive_fgets(struct archive *a, struct archive_read_buffer *b); +int _alpm_splitname(const char *target, pmpkg_t *pkg); +unsigned long _alpm_hash_sdbm(const char *str); +long _alpm_parsedate(const char *line);  #ifndef HAVE_STRSEP  char *strsep(char **, const char *);  #endif +#ifndef HAVE_STRNDUP +char *strndup(const char *s, size_t n); +#endif +  /* check exported library symbols with: nm -C -D <lib> */  #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: */ diff --git a/lib/libalpm/version.c b/lib/libalpm/version.c index fb327df3..eba66210 100644 --- a/lib/libalpm/version.c +++ b/lib/libalpm/version.c @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + *  Copyright (c) 2006-2011 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 @@ -23,23 +23,66 @@  /* libalpm */  #include "util.h" -/** Compare two version strings and determine which one is 'newer'. - * Returns a value comparable to the way strcmp works. Returns 1 - * if a is newer than b, 0 if a and b are the same version, or -1 - * if b is newer than a. - * - * This function has been adopted from the rpmvercmp function located - * at lib/rpmvercmp.c, and was most recently updated against rpm - * version 4.4.2.3. Small modifications have been made to make it more - * consistent with the libalpm coding style. - * - * Keep in mind that the pkgrel is only compared if it is available - * on both versions handed to this function. For example, comparing - * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield - * -1 as expected. This is mainly for supporting versioned dependencies - * that do not include the pkgrel. +/** + * Some functions in this file have been adopted from the rpm source, notably + * 'rpmvercmp' located at lib/rpmvercmp.c and 'parseEVR' located at + * lib/rpmds.c. It was most recently updated against rpm version 4.8.1. Small + * modifications have been made to make it more consistent with the libalpm + * coding style.   */ -int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b) + +/** + * Split EVR into epoch, version, and release components. + * @param evr		[epoch:]version[-release] string + * @retval *ep		pointer to epoch + * @retval *vp		pointer to version + * @retval *rp		pointer to release + */ +static void parseEVR(char *evr, const char **ep, const char **vp, +		const char **rp) +{ +	const char *epoch; +	const char *version; +	const char *release; +	char *s, *se; + +	s = evr; +	/* s points to epoch terminator */ +	while (*s && isdigit(*s)) s++; +	/* se points to version terminator */ +	se = strrchr(s, '-'); + +	if(*s == ':') { +		epoch = evr; +		*s++ = '\0'; +		version = s; +		if(*epoch == '\0') { +			epoch = "0"; +		} +	} else { +		/* different from RPM- always assume 0 epoch */ +		epoch = "0"; +		version = evr; +	} +	if(se) { +		*se++ = '\0'; +		release = se; +	} else { +		release = NULL; +	} + +	if(ep) *ep = epoch; +	if(vp) *vp = version; +	if(rp) *rp = release; +} + +/** + * Compare alpha and numeric segments of two versions. + * return 1: a is newer than b + *        0: a and b are the same version + *       -1: b is newer than a + */ +static int rpmvercmp(const char *a, const char *b)  {  	char oldch1, oldch2;  	char *str1, *str2; @@ -49,13 +92,6 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)  	int isnum;  	int ret = 0; -	/* libalpm added code. ensure our strings are not null */ -	if(!a) { -		if(!b) return(0); -		return(-1); -	} -	if(!b) return(1); -  	/* easy comparison to see if versions are identical */  	if(strcmp(a, b) == 0) return(0); @@ -147,22 +183,6 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)  		one = ptr1;  		*ptr2 = oldch2;  		two = ptr2; - -		/* libalpm added code. check if version strings have hit the pkgrel -		 * portion. depending on which strings have hit, take correct action. -		 * this is all based on the premise that we only have one dash in -		 * the version string, and it separates pkgver from pkgrel. */ -		if(*ptr1 == '-' && *ptr2 == '-') { -			/* no-op, continue comparing since we are equivalent throughout */ -		} else if(*ptr1 == '-') { -			/* ptr1 has hit the pkgrel and ptr2 has not. continue version -			 * comparison after stripping the pkgrel from ptr1. */ -			*ptr1 = '\0'; -		} else if(*ptr2 == '-') { -			/* ptr2 has hit the pkgrel and ptr1 has not. continue version -			 * comparison after stripping the pkgrel from ptr2. */ -			*ptr2 = '\0'; -		}  	}  	/* this catches the case where all numeric and alpha segments have */ @@ -179,7 +199,7 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)  	 * - if one is an alpha, two is newer.  	 * - otherwise one is newer.  	 * */ -	if ( ( !*one && !isalpha((int)*two) ) +	if ( (!*one && !isalpha((int)*two))  			|| isalpha((int)*one) ) {  		ret = -1;  	} else { @@ -192,4 +212,61 @@ cleanup:  	return(ret);  } +/** Compare two version strings and determine which one is 'newer'. + * Returns a value comparable to the way strcmp works. Returns 1 + * if a is newer than b, 0 if a and b are the same version, or -1 + * if b is newer than a. + * + * Different epoch values for version strings will override any further + * comparison. If no epoch is provided, 0 is assumed. + * + * Keep in mind that the pkgrel is only compared if it is available + * on both versions handed to this function. For example, comparing + * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield + * -1 as expected. This is mainly for supporting versioned dependencies + * that do not include the pkgrel. + */ +int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b) +{ +	char *full1, *full2; +	const char *epoch1, *ver1, *rel1; +	const char *epoch2, *ver2, *rel2; +	int ret; + +	/* ensure our strings are not null */ +	if(!a && !b) { +		return(0); +	} else if(!a) { +		return(-1); +	} else if(!b) { +		return(1); +	} +	/* another quick shortcut- if full version specs are equal */ +	if(strcmp(a, b) == 0) { +		return(0); +	} + +	/* Parse both versions into [epoch:]version[-release] triplets. We probably +	 * don't need epoch and release to support all the same magic, but it is +	 * easier to just run it all through the same code. */ +	full1 = strdup(a); +	full2 = strdup(b); + +	/* parseEVR modifies passed in version, so have to dupe it first */ +	parseEVR(full1, &epoch1, &ver1, &rel1); +	parseEVR(full2, &epoch2, &ver2, &rel2); + +	ret = rpmvercmp(epoch1, epoch2); +	if(ret == 0) { +		ret = rpmvercmp(ver1, ver2); +		if(ret == 0 && rel1 && rel2) { +			ret = rpmvercmp(rel1, rel2); +		} +	} + +	free(full1); +	free(full2); +	return(ret); +} +  /* vim: set ts=2 sw=2 noet: */ | 
