diff options
Diffstat (limited to 'lib/libalpm')
| -rw-r--r-- | lib/libalpm/add.c | 124 | ||||
| -rw-r--r-- | lib/libalpm/alpm.c | 4 | ||||
| -rw-r--r-- | lib/libalpm/alpm.h | 29 | ||||
| -rw-r--r-- | lib/libalpm/alpm_list.c | 13 | ||||
| -rw-r--r-- | lib/libalpm/alpm_list.h | 1 | ||||
| -rw-r--r-- | lib/libalpm/base64.c | 2 | ||||
| -rw-r--r-- | lib/libalpm/base64.h | 2 | ||||
| -rw-r--r-- | lib/libalpm/be_local.c | 27 | ||||
| -rw-r--r-- | lib/libalpm/be_package.c | 90 | ||||
| -rw-r--r-- | lib/libalpm/be_sync.c | 45 | ||||
| -rw-r--r-- | lib/libalpm/conflict.c | 23 | ||||
| -rw-r--r-- | lib/libalpm/db.h | 2 | ||||
| -rw-r--r-- | lib/libalpm/deps.c | 2 | ||||
| -rw-r--r-- | lib/libalpm/diskspace.c | 102 | ||||
| -rw-r--r-- | lib/libalpm/diskspace.h | 2 | ||||
| -rw-r--r-- | lib/libalpm/dload.c | 4 | ||||
| -rw-r--r-- | lib/libalpm/dload.h | 3 | ||||
| -rw-r--r-- | lib/libalpm/error.c | 4 | ||||
| -rw-r--r-- | lib/libalpm/handle.c | 2 | ||||
| -rw-r--r-- | lib/libalpm/handle.h | 6 | ||||
| -rw-r--r-- | lib/libalpm/package.c | 74 | ||||
| -rw-r--r-- | lib/libalpm/package.h | 9 | ||||
| -rw-r--r-- | lib/libalpm/remove.c | 20 | ||||
| -rw-r--r-- | lib/libalpm/signing.c | 22 | ||||
| -rw-r--r-- | lib/libalpm/sync.c | 199 | ||||
| -rw-r--r-- | lib/libalpm/util.c | 521 | ||||
| -rw-r--r-- | lib/libalpm/util.h | 25 | 
27 files changed, 842 insertions, 515 deletions
| diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 6c2f0cb6..78615bb1 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -22,7 +22,6 @@  #include <stdlib.h>  #include <errno.h> -#include <time.h>  #include <string.h>  #include <limits.h>  #include <fcntl.h> @@ -132,6 +131,18 @@ static int perform_extraction(alpm_handle_t *handle, struct archive *archive,  	return 0;  } +static int try_rename(alpm_handle_t *handle, const char *src, const char *dest) +{ +	if(rename(src, dest)) { +		_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), +				src, dest, strerror(errno)); +		alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", +				src, dest, strerror(errno)); +		return 1; +	} +	return 0; +} +  static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  		struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)  { @@ -146,8 +157,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  	entryname = archive_entry_pathname(entry);  	entrymode = archive_entry_mode(entry); -	memset(filename, 0, PATH_MAX); /* just to be sure */ -  	if(strcmp(entryname, ".INSTALL") == 0) {  		/* the install script goes inside the db */  		snprintf(filename, PATH_MAX, "%s%s-%s/install", @@ -170,7 +179,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  	}  	/* if a file is in NoExtract then we never extract it */ -	if(alpm_list_find_str(handle->noextract, entryname)) { +	if(alpm_list_find(handle->noextract, entryname, _alpm_fnmatch)) {  		_alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract, skipping extraction\n",  				entryname);  		alpm_logaction(handle, "note: %s is in NoExtract, skipping extraction\n", @@ -250,7 +259,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  		} else if(S_ISREG(entrymode)) {  			/* case 4,7: */  			/* if file is in NoUpgrade, don't touch it */ -			if(alpm_list_find_str(handle->noupgrade, entryname)) { +			if(alpm_list_find(handle->noupgrade, entryname, _alpm_fnmatch)) {  				notouch = 1;  			} else {  				alpm_backup_t *backup; @@ -282,17 +291,18 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  	STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1));  	if(needbackup) { -		char checkfile[PATH_MAX]; +		char *checkfile;  		char *hash_local = NULL, *hash_pkg = NULL; -		int ret; +		size_t len; -		snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); +		len = strlen(filename) + 10; +		MALLOC(checkfile, len, +				errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); +		snprintf(checkfile, len, "%s.paccheck", filename); -		ret = perform_extraction(handle, archive, entry, checkfile, entryname_orig); -		if(ret == 1) { -			/* error */ -			FREE(entryname_orig); -			return 1; +		if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) { +			errors++; +			goto needbackup_cleanup;  		}  		hash_local = alpm_compute_md5sum(filename); @@ -320,29 +330,26 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  			if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) {  				/* looks like we have a local file that has a different hash as the  				 * file in the package, move it to a .pacorig */ -				char newpath[PATH_MAX]; -				snprintf(newpath, PATH_MAX, "%s.pacorig", filename); +				char *newpath; +				size_t newlen = strlen(filename) + 9; +				MALLOC(newpath, newlen, +						errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); +				snprintf(newpath, newlen, "%s.pacorig", filename);  				/* move the existing file to the "pacorig" */ -				if(rename(filename, newpath)) { -					_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), -							filename, newpath, strerror(errno)); -					alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", -							filename, newpath, strerror(errno)); +				if(try_rename(handle, filename, newpath)) { +						errors++;  					errors++;  				} else {  					/* rename the file we extracted to the real name */ -					if(rename(checkfile, filename)) { -						_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), -								checkfile, filename, strerror(errno)); -						alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", -								checkfile, filename, strerror(errno)); +					if(try_rename(handle, checkfile, filename)) {  						errors++;  					} else {  						_alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath);  						alpm_logaction(handle, "warning: %s saved as %s\n", filename, newpath);  					}  				} +				free(newpath);  			} else {  				/* local file is identical to pkg one, so just remove pkg one */  				unlink(checkfile); @@ -356,11 +363,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  					_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",  							entryname_orig); -					if(rename(checkfile, filename)) { -						_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), -								checkfile, filename, strerror(errno)); -						alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", -								checkfile, filename, strerror(errno)); +					if(try_rename(handle, checkfile, filename)) {  						errors++;  					}  				} else { @@ -382,29 +385,30 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  				_alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n");  				unlink(checkfile);  			} else { -				char newpath[PATH_MAX]; +				char *newpath; +				size_t newlen = strlen(filename) + 8;  				_alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing"  						" new one with .pacnew ending\n"); -				snprintf(newpath, PATH_MAX, "%s.pacnew", filename); -				if(rename(checkfile, newpath)) { -					_alpm_log(handle, ALPM_LOG_ERROR, _("could not install %s as %s (%s)\n"), -							filename, newpath, strerror(errno)); -					alpm_logaction(handle, "error: could not install %s as %s (%s)\n", -							filename, newpath, strerror(errno)); +				MALLOC(newpath, newlen, +						errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); +				snprintf(newpath, newlen, "%s.pacnew", filename); +				if(try_rename(handle, checkfile, newpath)) { +					errors++;  				} else {  					_alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"),  							filename, newpath);  					alpm_logaction(handle, "warning: %s installed as %s\n",  							filename, newpath);  				} +				free(newpath);  			}  		} -		FREE(hash_local); -		FREE(hash_pkg); +needbackup_cleanup: +		free(checkfile); +		free(hash_local); +		free(hash_pkg);  	} else { -		int ret; -  		/* we didn't need a backup */  		if(notouch) {  			/* change the path to a .pacnew extension */ @@ -423,11 +427,11 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  			unlink(filename);  		} -		ret = perform_extraction(handle, archive, entry, filename, entryname_orig); -		if(ret == 1) { +		if(perform_extraction(handle, archive, entry, filename, entryname_orig)) {  			/* error */ -			FREE(entryname_orig); -			return 1; +			free(entryname_orig); +			errors++; +			return errors;  		}  		/* calculate an hash if this is in newpkg's backup */ @@ -444,7 +448,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive,  			backup->hash = newhash;  		}  	} -	FREE(entryname_orig); +	free(entryname_orig);  	return errors;  } @@ -521,31 +525,20 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,  	if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {  		struct archive *archive;  		struct archive_entry *entry; -		int cwdfd; +		struct stat buf; +		int fd, cwdfd;  		_alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n"); -		if((archive = archive_read_new()) == NULL) { -			handle->pm_errno = ALPM_ERR_LIBARCHIVE; -			ret = -1; -			goto cleanup; -		} - -		archive_read_support_compression_all(archive); -		archive_read_support_format_all(archive); - -		_alpm_log(handle, ALPM_LOG_DEBUG, "archive: %s\n", pkgfile); -		if(archive_read_open_filename(archive, pkgfile, -					ALPM_BUFFER_SIZE) != ARCHIVE_OK) { -			handle->pm_errno = ALPM_ERR_PKG_OPEN; +		fd = _alpm_open_archive(db->handle, pkgfile, &buf, +				&archive, ALPM_ERR_PKG_OPEN); +		if(fd < 0) {  			ret = -1;  			goto cleanup;  		}  		/* save the cwd so we can restore it later */ -		do { -			cwdfd = open(".", O_RDONLY); -		} while(cwdfd == -1 && errno == EINTR); +		OPEN(cwdfd, ".", O_RDONLY);  		if(cwdfd < 0) {  			_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));  		} @@ -554,6 +547,8 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,  		if(chdir(handle->root) != 0) {  			_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),  					handle->root, strerror(errno)); +			archive_read_finish(archive); +			CLOSE(fd);  			ret = -1;  			goto cleanup;  		} @@ -595,6 +590,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,  			errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);  		}  		archive_read_finish(archive); +		CLOSE(fd);  		/* restore the old cwd if we have it */  		if(cwdfd >= 0) { @@ -602,7 +598,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,  				_alpm_log(handle, ALPM_LOG_ERROR,  						_("could not restore working directory (%s)\n"), strerror(errno));  			} -			close(cwdfd); +			CLOSE(cwdfd);  		}  		if(errors) { diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index 38843342..e957f1aa 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -47,9 +47,9 @@   * @return a context handle on success, NULL on error, err will be set if provided   */  alpm_handle_t SYMEXPORT *alpm_initialize(const char *root, const char *dbpath, -		enum _alpm_errno_t *err) +		alpm_errno_t *err)  { -	enum _alpm_errno_t myerr; +	alpm_errno_t myerr;  	const char *lf = "db.lck";  	size_t lockfilelen;  	alpm_handle_t *myhandle = _alpm_handle_new(); diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index a93d4e3e..1751c81c 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -27,9 +27,9 @@  extern "C" {  #endif -#include <sys/types.h> /* for off_t */ -#include <time.h> /* for time_t */ -#include <stdarg.h> /* for va_list */ +#include <inttypes.h>  /* int64_t */ +#include <sys/types.h> /* off_t */ +#include <stdarg.h>    /* va_list */  #include <alpm_list.h> @@ -44,6 +44,8 @@ extern "C" {   * @{   */ +typedef int64_t alpm_time_t; +  /*   * Enumerations   * These ones are used in multiple contexts, so are forward-declared. @@ -222,8 +224,11 @@ typedef struct _alpm_pgpkey_t {  	char *uid;  	char *name;  	char *email; -	time_t created; -	time_t expires; +	alpm_time_t created; +	alpm_time_t expires; +	unsigned int length; +	unsigned int revoked; +	char pubkey_algo;  } alpm_pgpkey_t;  /** Signature result. Contains the key, status, and validity of a given @@ -754,13 +759,13 @@ const char *alpm_pkg_get_url(alpm_pkg_t *pkg);   * @param pkg a pointer to package   * @return the timestamp of the build time   */ -time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg); +alpm_time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg);  /** Returns the install timestamp of the package.   * @param pkg a pointer to package   * @return the timestamp of the install time   */ -time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg); +alpm_time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg);  /** Returns the packager's name.   * @param pkg a pointer to package @@ -1113,7 +1118,7 @@ char *alpm_compute_sha256sum(const char *filename);  /** @addtogroup alpm_api_errors Error Codes   * @{   */ -enum _alpm_errno_t { +typedef enum _alpm_errno_t {  	ALPM_ERR_MEMORY = 1,  	ALPM_ERR_SYSTEM,  	ALPM_ERR_BADPERMS, @@ -1177,19 +1182,19 @@ enum _alpm_errno_t {  	ALPM_ERR_LIBCURL,  	ALPM_ERR_EXTERNAL_DOWNLOAD,  	ALPM_ERR_GPGME -}; +} alpm_errno_t;  /** Returns the current error code from the handle. */ -enum _alpm_errno_t alpm_errno(alpm_handle_t *handle); +alpm_errno_t alpm_errno(alpm_handle_t *handle);  /** Returns the string corresponding to an error number. */ -const char *alpm_strerror(enum _alpm_errno_t err); +const char *alpm_strerror(alpm_errno_t err);  /* End of alpm_api_errors */  /** @} */  alpm_handle_t *alpm_initialize(const char *root, const char *dbpath, -		enum _alpm_errno_t *err); +		alpm_errno_t *err);  int alpm_release(alpm_handle_t *handle);  enum alpm_caps { diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index 15286aa1..cad6d096 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -576,19 +576,6 @@ alpm_list_t SYMEXPORT *alpm_list_last(const alpm_list_t *list)  	}  } -/** - * @brief Get the data member of a list node. - * - * @param node the list node - * - * @return the contained data, or NULL if none - */ -void SYMEXPORT *alpm_list_getdata(const alpm_list_t *node) -{ -	if(node == NULL) return NULL; -	return node->data; -} -  /* Misc */  /** diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index cd7b0291..9f69e2c2 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -71,7 +71,6 @@ 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_previous(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 */  size_t alpm_list_count(const alpm_list_t *list); diff --git a/lib/libalpm/base64.c b/lib/libalpm/base64.c index 5c9fa814..0d29f656 100644 --- a/lib/libalpm/base64.c +++ b/lib/libalpm/base64.c @@ -62,6 +62,7 @@ static const unsigned char base64_dec_map[128] =       49,  50,  51, 127, 127, 127, 127, 127  }; +#if 0  /*   * Encode a buffer into base64 format   */ @@ -124,6 +125,7 @@ int base64_encode( unsigned char *dst, size_t *dlen,      return( 0 );  } +#endif  /*   * Decode a base64-formatted buffer diff --git a/lib/libalpm/base64.h b/lib/libalpm/base64.h index 406aefa1..df684ab7 100644 --- a/lib/libalpm/base64.h +++ b/lib/libalpm/base64.h @@ -30,6 +30,7 @@  #define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL               -0x0010  /**< Output buffer too small. */  #define POLARSSL_ERR_BASE64_INVALID_CHARACTER              -0x0012  /**< Invalid character in input. */ +#if 0  /**   * \brief          Encode a buffer into base64 format   * @@ -47,6 +48,7 @@   */  int base64_encode( unsigned char *dst, size_t *dlen,                     const unsigned char *src, size_t slen ); +#endif  /**   * \brief          Decode a base64-formatted buffer diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 56cf38bb..606f9e1a 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -28,7 +28,6 @@  #include <stdint.h> /* intmax_t */  #include <sys/stat.h>  #include <dirent.h> -#include <time.h>  #include <limits.h> /* PATH_MAX */  /* libalpm */ @@ -69,13 +68,13 @@ static const char *_cache_get_url(alpm_pkg_t *pkg)  	return pkg->url;  } -static time_t _cache_get_builddate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_builddate(alpm_pkg_t *pkg)  {  	LAZY_LOAD(INFRQ_DESC, 0);  	return pkg->builddate;  } -static time_t _cache_get_installdate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_installdate(alpm_pkg_t *pkg)  {  	LAZY_LOAD(INFRQ_DESC, 0);  	return pkg->installdate; @@ -475,7 +474,8 @@ static int local_db_populate(alpm_db_t *db)  }  /* Note: the return value must be freed by the caller */ -char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filename) +char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, +		const char *filename)  {  	size_t len;  	char *pkgpath; @@ -638,10 +638,11 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)  		while(fgets(line, sizeof(line), fp)) {  			_alpm_strip_newline(line);  			if(strcmp(line, "%FILES%") == 0) { -				size_t files_count = 0, files_size = 0; +				size_t files_count = 0, files_size = 0, len;  				alpm_file_t *files = NULL; -				while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line)) { +				while(fgets(line, sizeof(line), fp) && +						(len = _alpm_strip_newline(line))) {  					if(files_count >= files_size) {  						size_t old_size = files_size;  						if(files_size == 0) { @@ -659,8 +660,14 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)  						memset(files + old_size, 0,  								sizeof(alpm_file_t) * (files_size - old_size));  					} -					STRDUP(files[files_count].name, line, goto error); -					/* TODO: lstat file, get mode/size */ +					/* since we know the length of the file string already, +					 * we can do malloc + memcpy rather than strdup */ +					files[files_count].name = malloc(len + 1); +					if(files[files_count].name == NULL) { +						ALLOC_FAIL(len); +						goto error; +					} +					memcpy(files[files_count].name, line, len + 1);  					files_count++;  				}  				/* attempt to hand back any memory we don't need */ @@ -794,11 +801,11 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq  		}  		if(info->builddate) {  			fprintf(fp, "%%BUILDDATE%%\n" -							"%ld\n\n", info->builddate); +							"%jd\n\n", (intmax_t)info->builddate);  		}  		if(info->installdate) {  			fprintf(fp, "%%INSTALLDATE%%\n" -							"%ld\n\n", info->installdate); +							"%jd\n\n", (intmax_t)info->installdate);  		}  		if(info->packager) {  			fprintf(fp, "%%PACKAGER%%\n" diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index 4d9d0e82..4f530e0b 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -23,6 +23,9 @@  #include <stdlib.h>  #include <string.h>  #include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h>  /* libarchive */  #include <archive.h> @@ -37,6 +40,11 @@  #include "package.h"  #include "deps.h" /* _alpm_splitdep */ +struct package_changelog { +	struct archive *archive; +	int fd; +}; +  /**   * Open a package changelog for reading. Similar to fopen in functionality,   * except that the returned 'file stream' is from an archive. @@ -47,31 +55,38 @@ static void *_package_changelog_open(alpm_pkg_t *pkg)  {  	ASSERT(pkg != NULL, return NULL); -	struct archive *archive = NULL; +	struct package_changelog *changelog; +	struct archive *archive;  	struct archive_entry *entry;  	const char *pkgfile = pkg->origin_data.file; +	struct stat buf; +	int fd; -	if((archive = archive_read_new()) == NULL) { -		RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, NULL); -	} - -	archive_read_support_compression_all(archive); -	archive_read_support_format_all(archive); - -	if(archive_read_open_filename(archive, pkgfile, -				ALPM_BUFFER_SIZE) != ARCHIVE_OK) { -		RET_ERR(pkg->handle, ALPM_ERR_PKG_OPEN, NULL); +	fd = _alpm_open_archive(pkg->handle, pkgfile, &buf, +			&archive, ALPM_ERR_PKG_OPEN); +	if(fd < 0) { +		return 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; +			changelog = malloc(sizeof(struct package_changelog)); +			if(!changelog) { +				pkg->handle->pm_errno = ALPM_ERR_MEMORY; +				archive_read_finish(archive); +				CLOSE(fd); +				return NULL; +			} +			changelog->archive = archive; +			changelog->fd = fd; +			return changelog;  		}  	}  	/* we didn't find a changelog */  	archive_read_finish(archive); +	CLOSE(fd);  	errno = ENOENT;  	return NULL; @@ -89,7 +104,8 @@ static void *_package_changelog_open(alpm_pkg_t *pkg)  static size_t _package_changelog_read(void *ptr, size_t size,  		const alpm_pkg_t UNUSED *pkg, void *fp)  { -	ssize_t sret = archive_read_data((struct archive *)fp, ptr, size); +	struct package_changelog *changelog = fp; +	ssize_t sret = archive_read_data(changelog->archive, ptr, size);  	/* Report error (negative values) */  	if(sret < 0) {  		RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, 0); @@ -107,7 +123,12 @@ static size_t _package_changelog_read(void *ptr, size_t size,   */  static int _package_changelog_close(const alpm_pkg_t UNUSED *pkg, void *fp)  { -	return archive_read_finish((struct archive *)fp); +	int ret; +	struct package_changelog *changelog = fp; +	ret = archive_read_finish(changelog->archive); +	CLOSE(changelog->fd); +	free(changelog); +	return ret;  }  /** Package file operations struct accessor. We implement this as a method @@ -355,7 +376,7 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle,  alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,  		const char *pkgfile, int full)  { -	int ret, config = 0; +	int ret, fd, config = 0;  	struct archive *archive;  	struct archive_entry *entry;  	alpm_pkg_t *newpkg = NULL; @@ -367,33 +388,22 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,  		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL);  	} -	/* attempt to stat the package file, ensure it exists */ -	if(stat(pkgfile, &st) == 0) { -		newpkg = _alpm_pkg_new(); -		if(newpkg == NULL) { -			RET_ERR(handle, ALPM_ERR_MEMORY, NULL); +	fd = _alpm_open_archive(handle, pkgfile, &st, &archive, ALPM_ERR_PKG_OPEN); +	if(fd < 0) { +		if(errno == ENOENT) { +			handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND;  		} -		newpkg->filename = strdup(pkgfile); -		newpkg->size = st.st_size; -	} else { -		/* couldn't stat the pkgfile, return an error */ -		RET_ERR(handle, ALPM_ERR_PKG_NOT_FOUND, NULL); -	} - -	/* try to create an archive object to read in the package */ -	if((archive = archive_read_new()) == NULL) { -		alpm_pkg_free(newpkg); -		RET_ERR(handle, ALPM_ERR_LIBARCHIVE, NULL); +		goto error;  	} -	archive_read_support_compression_all(archive); -	archive_read_support_format_all(archive); - -	if(archive_read_open_filename(archive, pkgfile, -				ALPM_BUFFER_SIZE) != ARCHIVE_OK) { -		alpm_pkg_free(newpkg); -		RET_ERR(handle, ALPM_ERR_PKG_OPEN, NULL); +	newpkg = _alpm_pkg_new(); +	if(newpkg == NULL) { +		handle->pm_errno = ALPM_ERR_MEMORY; +		goto error;  	} +	STRDUP(newpkg->filename, pkgfile, +			handle->pm_errno = ALPM_ERR_MEMORY; goto error); +	newpkg->size = st.st_size;  	_alpm_log(handle, ALPM_LOG_DEBUG, "starting package load for %s\n", pkgfile); @@ -476,6 +486,7 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,  	}  	archive_read_finish(archive); +	CLOSE(fd);  	/* internal fields for package struct */  	newpkg->origin = PKG_FROM_FILE; @@ -504,6 +515,9 @@ pkg_invalid:  error:  	_alpm_pkg_free(newpkg);  	archive_read_finish(archive); +	if(fd >= 0) { +		CLOSE(fd); +	}  	return NULL;  } diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 3c990246..54c4f879 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -21,7 +21,9 @@  #include "config.h"  #include <errno.h> +#include <sys/types.h>  #include <sys/stat.h> +#include <fcntl.h>  #include <unistd.h>  /* libarchive */ @@ -212,6 +214,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)  		/* print server + filename into a buffer */  		len = strlen(server) + strlen(db->treename) + 5; +		/* TODO fix leak syncpath and umask unset */  		MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));  		snprintf(payload.fileurl, len, "%s/%s.db", server, db->treename);  		payload.handle = handle; @@ -234,6 +237,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)  			/* if we downloaded a DB, we want the .sig from the same server */  			/* print server + filename into a buffer (leave space for .sig) */  			len = strlen(server) + strlen(db->treename) + 9; +			/* TODO fix leak syncpath and umask unset */  			MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));  			snprintf(payload.fileurl, len, "%s/%s.db.sig", server, db->treename);  			payload.handle = handle; @@ -411,7 +415,7 @@ static int sync_db_populate(alpm_db_t *db)  {  	const char *dbpath;  	size_t est_count; -	int count = 0; +	int count = -1, fd;  	struct stat buf;  	struct archive *archive;  	struct archive_entry *entry; @@ -423,38 +427,24 @@ static int sync_db_populate(alpm_db_t *db)  	if(db->status & DB_STATUS_MISSING) {  		RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);  	} - -	if((archive = archive_read_new()) == NULL) { -		RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1); -	} - -	archive_read_support_compression_all(archive); -	archive_read_support_format_all(archive); -  	dbpath = _alpm_db_path(db);  	if(!dbpath) {  		/* pm_errno set in _alpm_db_path() */  		return -1;  	} -	_alpm_log(db->handle, ALPM_LOG_DEBUG, "opening database archive %s\n", dbpath); - -	if(archive_read_open_filename(archive, dbpath, -				ALPM_BUFFER_SIZE) != ARCHIVE_OK) { -		_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath, -				archive_error_string(archive)); -		archive_read_finish(archive); -		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); -	} -	if(stat(dbpath, &buf) != 0) { -		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); +	fd = _alpm_open_archive(db->handle, dbpath, &buf, +			&archive, ALPM_ERR_DB_OPEN); +	if(fd < 0) { +		goto cleanup;  	}  	est_count = estimate_package_count(&buf, archive);  	/* initialize hash at 66% full */  	db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2);  	if(db->pkgcache == NULL) { -		RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); +		db->handle->pm_errno = ALPM_ERR_MEMORY; +		goto cleanup;  	}  	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { @@ -473,14 +463,19 @@ static int sync_db_populate(alpm_db_t *db)  	}  	count = alpm_list_count(db->pkgcache->list); -  	if(count > 0) { -		db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp); +		db->pkgcache->list = alpm_list_msort(db->pkgcache->list, +				(size_t)count, _alpm_pkg_cmp);  	} -	archive_read_finish(archive); -	_alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n", +	_alpm_log(db->handle, ALPM_LOG_DEBUG, +			"added %d packages to package cache for db '%s'\n",  			count, db->treename); +cleanup: +	archive_read_finish(archive); +	if(fd >= 0) { +		CLOSE(fd); +	}  	return count;  } diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 32f6f303..5703aba8 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -318,12 +318,16 @@ const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist,  		const char *name)  {  	size_t i; -	const alpm_file_t *file = filelist->files; -	for(i = 0; i < filelist->count; i++) { +	const alpm_file_t *file; + +	if(!filelist) { +		return NULL; +	} + +	for(file = filelist->files, i = 0; i < filelist->count; file++, i++) {  		if(strcmp(file->name, name) == 0) {  			return file;  		} -		file++;  	}  	return NULL;  } @@ -383,11 +387,14 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,  	alpm_list_t *i, *conflicts = NULL;  	size_t numtargs = alpm_list_count(upgrade);  	size_t current; +	size_t rootlen;  	if(!upgrade) {  		return NULL;  	} +	rootlen = strlen(handle->root); +  	/* TODO this whole function needs a huge change, which hopefully will  	 * be possible with real transactions. Right now we only do half as much  	 * here as we do when we actually extract files in add.c with our 12 @@ -461,8 +468,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,  			int resolved_conflict = 0;  			struct stat lsbuf;  			char path[PATH_MAX]; +			size_t pathlen; -			snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); +			pathlen = snprintf(path, PATH_MAX, "%s%s", handle->root, filestr);  			/* stat the file - if it exists, do some checks */  			if(_alpm_lstat(path, &lsbuf) != 0) { @@ -486,10 +494,10 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,  				/* if we made it to here, we want all subsequent path comparisons to  				 * not include the trailing slash. This allows things like file ->  				 * directory replacements. */ -				path[strlen(path) - 1] = '\0'; +				path[pathlen - 1] = '\0';  			} -			relative_path = path + strlen(handle->root); +			relative_path = path + rootlen;  			/* Check remove list (will we remove the conflicting local file?) */  			for(k = remove; k && !resolved_conflict; k = k->next) { @@ -542,9 +550,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,  			 * components can be safely checked as all directories are "unowned". */  			if(!resolved_conflict && dbpkg && !S_ISLNK(lsbuf.st_mode)) {  				char *rpath = calloc(PATH_MAX, sizeof(char)); -				const char *relative_rpath;  				if(realpath(path, rpath)) { -					relative_rpath = rpath + strlen(handle->root); +					const char *relative_rpath = rpath + rootlen;  					if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) {  						_alpm_log(handle, ALPM_LOG_DEBUG,  								"package contained the resolved realpath\n"); diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 224bfbeb..a1249d3e 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -22,8 +22,6 @@  #ifndef _ALPM_DB_H  #define _ALPM_DB_H -#include <time.h> -  /* libarchive */  #include <archive.h>  #include <archive_entry.h> diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 89f6d691..9f7e9028 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -395,7 +395,7 @@ int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep)  			/* any version will satisfy the requirement */  			satisfy = (provision->name_hash == dep->name_hash  					&& strcmp(provision->name, dep->name) == 0); -		} else if (provision->mod == ALPM_DEP_MOD_EQ) { +		} else if(provision->mod == ALPM_DEP_MOD_EQ) {  			/* provision specifies a version, so try it out */  			satisfy = (provision->name_hash == dep->name_hash  					&& strcmp(provision->name, dep->name) == 0 diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index fe2036d5..cfd6402c 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -55,6 +55,17 @@ static int mount_point_cmp(const void *p1, const void *p2)  	return -strcmp(mp1->mount_dir, mp2->mount_dir);  } +static void mount_point_list_free(alpm_list_t *mount_points) +{ +	alpm_list_t *i; + +	for(i = mount_points; i; i = i->next) { +		alpm_mountpoint_t *data = i->data; +		FREE(data->mount_dir); +	} +	FREELIST(mount_points); +} +  static alpm_list_t *mount_point_list(alpm_handle_t *handle)  {  	alpm_list_t *mount_points = NULL, *ptr; @@ -232,6 +243,72 @@ static int calculate_installed_size(alpm_handle_t *handle,  	return 0;  } +static int check_mountpoint(alpm_handle_t *handle, alpm_mountpoint_t *mp) +{ +	/* cushion is roughly min(5% capacity, 20MiB) */ +	fsblkcnt_t fivepc = (mp->fsp.f_blocks / 20) + 1; +	fsblkcnt_t twentymb = (20 * 1024 * 1024 / mp->fsp.f_bsize) + 1; +	fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb; +	blkcnt_t needed = mp->max_blocks_needed + cushion; + +	_alpm_log(handle, ALPM_LOG_DEBUG, +			"partition %s, needed %jd, cushion %ju, free %ju\n", +			mp->mount_dir, (intmax_t)mp->max_blocks_needed, +			(uintmax_t)cushion, (uintmax_t)mp->fsp.f_bfree); +	if(needed >= 0 && (fsblkcnt_t)needed > mp->fsp.f_bfree) { +		_alpm_log(handle, ALPM_LOG_ERROR, +				_("Partition %s too full: %jd blocks needed, %jd blocks free\n"), +				mp->mount_dir, (intmax_t)needed, (uintmax_t)mp->fsp.f_bfree); +		return 1; +	} +	return 0; +} + +int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir, +		size_t num_files, off_t *file_sizes) +{ +	alpm_list_t *mount_points; +	alpm_mountpoint_t *cachedir_mp; +	size_t j; +	int error = 0; + +	mount_points = mount_point_list(handle); +	if(mount_points == NULL) { +		_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n")); +		return -1; +	} + +	cachedir_mp = match_mount_point(mount_points, cachedir); +	if(cachedir == NULL) { +		_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine cachedir mount point %s\n"), +				cachedir); +		error = 1; +		goto finish; +	} + +	/* there's no need to check for a R/O mounted filesystem here, as +	 * _alpm_filecache_setup will never give us a non-writable directory */ + +	/* round up the size of each file to the nearest block and accumulate */ +	for(j = 0; j < num_files; j++) { +		cachedir_mp->max_blocks_needed += (file_sizes[j] + cachedir_mp->fsp.f_bsize + 1) / +			cachedir_mp->fsp.f_bsize; +	} + +	if(check_mountpoint(handle, cachedir_mp)) { +		error = 1; +	} + +finish: +	mount_point_list_free(mount_points); + +	if(error) { +		RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); +	} + +	return 0; +} +  int _alpm_check_diskspace(alpm_handle_t *handle)  {  	alpm_list_t *mount_points, *i; @@ -300,32 +377,13 @@ int _alpm_check_diskspace(alpm_handle_t *handle)  			_alpm_log(handle, ALPM_LOG_ERROR, _("Partition %s is mounted read only\n"),  					data->mount_dir);  			error = 1; -		} else if(data->used & USED_INSTALL) { -			/* cushion is roughly min(5% capacity, 20MiB) */ -			fsblkcnt_t fivepc = (data->fsp.f_blocks / 20) + 1; -			fsblkcnt_t twentymb = (20 * 1024 * 1024 / data->fsp.f_bsize) + 1; -			fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb; -			blkcnt_t needed = data->max_blocks_needed + cushion; - -			_alpm_log(handle, ALPM_LOG_DEBUG, -					"partition %s, needed %jd, cushion %ju, free %ju\n", -					data->mount_dir, (intmax_t)data->max_blocks_needed, -					(uintmax_t)cushion, (uintmax_t)data->fsp.f_bfree); -			if(needed >= 0 && (fsblkcnt_t)needed > data->fsp.f_bfree) { -				_alpm_log(handle, ALPM_LOG_ERROR, -						_("Partition %s too full: %jd blocks needed, %jd blocks free\n"), -						data->mount_dir, (intmax_t)needed, (uintmax_t)data->fsp.f_bfree); -				error = 1; -			} +		} else if(data->used & USED_INSTALL && check_mountpoint(handle, data)) { +			error = 1;  		}  	}  finish: -	for(i = mount_points; i; i = i->next) { -		alpm_mountpoint_t *data = i->data; -		FREE(data->mount_dir); -	} -	FREELIST(mount_points); +	mount_point_list_free(mount_points);  	if(error) {  		RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); diff --git a/lib/libalpm/diskspace.h b/lib/libalpm/diskspace.h index 5944bb17..a613e232 100644 --- a/lib/libalpm/diskspace.h +++ b/lib/libalpm/diskspace.h @@ -50,6 +50,8 @@ typedef struct __alpm_mountpoint_t {  } alpm_mountpoint_t;  int _alpm_check_diskspace(alpm_handle_t *handle); +int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir, +		size_t num_files, off_t *file_sizes);  #endif /* _ALPM_DISKSPACE_H */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 29285903..bcbc8095 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -306,9 +306,7 @@ static FILE *create_tempfile(struct dload_payload *payload, const char *localpat  			fchmod(fd, ~(_getumask()) & 0666) ||  			!(fp = fdopen(fd, payload->tempfile_openmode))) {  		unlink(randpath); -		if(fd >= 0) { -			close(fd); -		} +		CLOSE(fd);  		_alpm_log(payload->handle, ALPM_LOG_ERROR,  				_("failed to create temporary file for download\n"));  		return NULL; diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index f5f2cd9c..9ab90b42 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -23,8 +23,6 @@  #include "alpm_list.h"  #include "alpm.h" -#include <time.h> -  struct dload_payload {  	alpm_handle_t *handle;  	const char *tempfile_openmode; @@ -40,6 +38,7 @@ struct dload_payload {  	int allow_resume;  	int errors_ok;  	int unlink_on_fail; +	alpm_list_t *servers;  #ifdef HAVE_LIBCURL  	CURLcode curlerr;       /* last error produced by curl */  #endif diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index b3f56819..044dec7c 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -29,12 +29,12 @@  #include "alpm.h"  #include "handle.h" -enum _alpm_errno_t SYMEXPORT alpm_errno(alpm_handle_t *handle) +alpm_errno_t SYMEXPORT alpm_errno(alpm_handle_t *handle)  {  	return handle->pm_errno;  } -const char SYMEXPORT *alpm_strerror(enum _alpm_errno_t err) +const char SYMEXPORT *alpm_strerror(alpm_errno_t err)  {  	switch(err) {  		/* System */ diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 7402be50..01f59555 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -339,7 +339,7 @@ static char *canonicalize_path(const char *path) {  	return new_path;  } -enum _alpm_errno_t _alpm_set_directory_option(const char *value, +alpm_errno_t _alpm_set_directory_option(const char *value,  		char **storage, int must_exist)   {  	struct stat st; diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 8477dcae..1f147d6e 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -86,14 +86,14 @@ struct __alpm_handle_t {  	alpm_list_t *ignoregroup; /* List of groups to ignore */  	/* options */ -	int usesyslog;           /* Use syslog instead of logfile? */ /* TODO move to frontend */  	char *arch;              /* Architecture of packages we should allow */ +	int usesyslog;           /* Use syslog instead of logfile? */ /* TODO move to frontend */  	int usedelta;            /* Download deltas if possible */  	int checkspace;          /* Check disk space before installing */  	alpm_siglevel_t siglevel;   /* Default signature verification level */  	/* error code */ -	enum _alpm_errno_t pm_errno; +	alpm_errno_t pm_errno;  };  alpm_handle_t *_alpm_handle_new(void); @@ -102,7 +102,7 @@ void _alpm_handle_free(alpm_handle_t *handle);  int _alpm_handle_lock(alpm_handle_t *handle);  int _alpm_handle_unlock(alpm_handle_t *handle); -enum _alpm_errno_t _alpm_set_directory_option(const char *value, +alpm_errno_t _alpm_set_directory_option(const char *value,  		char **storage, int must_exist);  #endif /* _ALPM_HANDLE_H */ diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index a5ff238f..e96177a2 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -87,12 +87,12 @@ int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg)   * populated package structures. */  static const char *_pkg_get_desc(alpm_pkg_t *pkg)        { return pkg->desc; }  static const char *_pkg_get_url(alpm_pkg_t *pkg)         { return pkg->url; } -static time_t _pkg_get_builddate(alpm_pkg_t *pkg)        { return pkg->builddate; } -static time_t _pkg_get_installdate(alpm_pkg_t *pkg)      { return pkg->installdate; } +static alpm_time_t _pkg_get_builddate(alpm_pkg_t *pkg)   { return pkg->builddate; } +static alpm_time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; }  static const char *_pkg_get_packager(alpm_pkg_t *pkg)    { return pkg->packager; }  static const char *_pkg_get_arch(alpm_pkg_t *pkg)        { return pkg->arch; }  static off_t _pkg_get_isize(alpm_pkg_t *pkg)             { return pkg->isize; } -static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg)    { return pkg->reason; } +static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg) { return pkg->reason; }  static int _pkg_has_scriptlet(alpm_pkg_t *pkg)           { return pkg->scriptlet; }  static alpm_list_t *_pkg_get_licenses(alpm_pkg_t *pkg)   { return pkg->licenses; } @@ -200,14 +200,14 @@ const char SYMEXPORT *alpm_pkg_get_url(alpm_pkg_t *pkg)  	return pkg->ops->get_url(pkg);  } -time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg) +alpm_time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg)  {  	ASSERT(pkg != NULL, return -1);  	pkg->handle->pm_errno = 0;  	return pkg->ops->get_builddate(pkg);  } -time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg) +alpm_time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg)  {  	ASSERT(pkg != NULL, return -1);  	pkg->handle->pm_errno = 0; @@ -461,6 +461,15 @@ alpm_pkg_t *_alpm_pkg_new(void)  	return pkg;  } +static alpm_list_t *list_depdup(alpm_list_t *old) +{ +	alpm_list_t *i, *new = NULL; +	for(i = old; i; i = i->next) { +		new = alpm_list_add(new, _alpm_dep_dup(i->data)); +	} +	return new; +} +  /**   * Duplicate a package data struct.   * @param pkg the package to duplicate @@ -509,10 +518,19 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr)  	newpkg->reason = pkg->reason;  	newpkg->licenses   = alpm_list_strdup(pkg->licenses); -	for(i = pkg->replaces; i; i = i->next) { -		newpkg->replaces = alpm_list_add(newpkg->replaces, _alpm_dep_dup(i->data)); -	} +	newpkg->replaces   = list_depdup(pkg->replaces);  	newpkg->groups     = alpm_list_strdup(pkg->groups); +	for(i = pkg->backup; i; i = i->next) { +		newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); +	} +	newpkg->depends    = list_depdup(pkg->depends); +	newpkg->optdepends = alpm_list_strdup(pkg->optdepends); +	newpkg->conflicts  = list_depdup(pkg->conflicts); +	newpkg->provides   = list_depdup(pkg->provides); +	for(i = pkg->deltas; i; i = i->next) { +		newpkg->deltas = alpm_list_add(newpkg->deltas, _alpm_delta_dup(i->data)); +	} +  	if(pkg->files.count) {  		size_t filenum;  		size_t len = sizeof(alpm_file_t) * pkg->files.count; @@ -525,22 +543,6 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr)  		}  		newpkg->files.count = pkg->files.count;  	} -	for(i = pkg->backup; i; i = i->next) { -		newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); -	} -	for(i = pkg->depends; i; i = i->next) { -		newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data)); -	} -	newpkg->optdepends = alpm_list_strdup(pkg->optdepends); -	for(i = pkg->conflicts; i; i = i->next) { -		newpkg->conflicts = alpm_list_add(newpkg->conflicts, _alpm_dep_dup(i->data)); -	} -	for(i = pkg->provides; i; i = i->next) { -		newpkg->provides = alpm_list_add(newpkg->provides, _alpm_dep_dup(i->data)); -	} -	for(i = pkg->deltas; i; i = i->next) { -		newpkg->deltas = alpm_list_add(newpkg->deltas, _alpm_delta_dup(i->data)); -	}  	/* internal */  	newpkg->infolevel = pkg->infolevel; @@ -561,6 +563,12 @@ cleanup:  	RET_ERR(pkg->handle, ALPM_ERR_MEMORY, -1);  } +static void free_deplist(alpm_list_t *deps) +{ +	alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_dep_free); +	alpm_list_free(deps); +} +  void _alpm_pkg_free(alpm_pkg_t *pkg)  {  	if(pkg == NULL) { @@ -579,8 +587,7 @@ void _alpm_pkg_free(alpm_pkg_t *pkg)  	FREE(pkg->arch);  	FREELIST(pkg->licenses); -	alpm_list_free_inner(pkg->replaces, (alpm_list_fn_free)_alpm_dep_free); -	alpm_list_free(pkg->replaces); +	free_deplist(pkg->replaces);  	FREELIST(pkg->groups);  	if(pkg->files.count) {  		size_t i; @@ -591,13 +598,10 @@ void _alpm_pkg_free(alpm_pkg_t *pkg)  	}  	alpm_list_free_inner(pkg->backup, (alpm_list_fn_free)_alpm_backup_free);  	alpm_list_free(pkg->backup); -	alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free); -	alpm_list_free(pkg->depends); +	free_deplist(pkg->depends);  	FREELIST(pkg->optdepends); -	alpm_list_free_inner(pkg->conflicts, (alpm_list_fn_free)_alpm_dep_free); -	alpm_list_free(pkg->conflicts); -	alpm_list_free_inner(pkg->provides, (alpm_list_fn_free)_alpm_dep_free); -	alpm_list_free(pkg->provides); +	free_deplist(pkg->conflicts); +	free_deplist(pkg->provides);  	alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free);  	alpm_list_free(pkg->deltas);  	alpm_list_free(pkg->delta_path); @@ -690,14 +694,14 @@ int _alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg)  	alpm_list_t *groups = NULL;  	/* first see if the package is ignored */ -	if(alpm_list_find_str(handle->ignorepkg, pkg->name)) { +	if(alpm_list_find(handle->ignorepkg, pkg->name, _alpm_fnmatch)) {  		return 1;  	}  	/* next see if the package is in a group that is ignored */ -	for(groups = handle->ignoregroup; groups; groups = groups->next) { +	for(groups = alpm_pkg_get_groups(pkg); groups; groups = groups->next) {  		char *grp = groups->data; -		if(alpm_list_find_str(alpm_pkg_get_groups(pkg), grp)) { +		if(alpm_list_find(handle->ignoregroup, grp, _alpm_fnmatch)) {  			return 1;  		}  	} diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index eff7d898..82a83264 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -27,7 +27,6 @@  #include "config.h" /* ensure off_t is correct length */  #include <sys/types.h> /* off_t */ -#include <time.h> /* time_t */  #include "alpm.h"  #include "backup.h" @@ -44,8 +43,8 @@  struct pkg_operations {  	const char *(*get_desc) (alpm_pkg_t *);  	const char *(*get_url) (alpm_pkg_t *); -	time_t (*get_builddate) (alpm_pkg_t *); -	time_t (*get_installdate) (alpm_pkg_t *); +	alpm_time_t (*get_builddate) (alpm_pkg_t *); +	alpm_time_t (*get_installdate) (alpm_pkg_t *);  	const char *(*get_packager) (alpm_pkg_t *);  	const char *(*get_arch) (alpm_pkg_t *);  	off_t (*get_isize) (alpm_pkg_t *); @@ -89,8 +88,8 @@ struct __alpm_pkg_t {  	char *base64_sig;  	char *arch; -	time_t builddate; -	time_t installdate; +	alpm_time_t builddate; +	alpm_time_t installdate;  	off_t size;  	off_t isize; diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 44f3ee93..d7e06bc8 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -216,7 +216,7 @@ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file,  {  	char filepath[PATH_MAX]; -	if(alpm_list_find_str(skip_remove, file->name)) { +	if(alpm_list_find(skip_remove, file->name, _alpm_fnmatch)) {  		/* return success because we will never actually remove this file */  		return 1;  	} @@ -239,8 +239,9 @@ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file,  /* Helper function for iterating through a package's file and deleting them   * Used by _alpm_remove_commit. */ -static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, -		const alpm_file_t *fileobj, alpm_list_t *skip_remove, int nosave) +static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, +		alpm_pkg_t *newpkg, const alpm_file_t *fileobj, alpm_list_t *skip_remove, +		int nosave)  {  	struct stat buf;  	char file[PATH_MAX]; @@ -250,7 +251,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,  	/* check the remove skip list before removing the file.  	 * see the big comment block in db_find_fileconflicts() for an  	 * explanation. */ -	if(alpm_list_find_str(skip_remove, fileobj->name)) { +	if(alpm_list_find(skip_remove, fileobj->name, _alpm_fnmatch)) {  		_alpm_log(handle, ALPM_LOG_DEBUG,  				"%s is in skip_remove, skipping removal\n", file);  		return 1; @@ -274,6 +275,10 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,  		} else if(files < 0) {  			_alpm_log(handle, ALPM_LOG_DEBUG,  					"keeping directory %s (could not count files)\n", file); +		} else if(newpkg && _alpm_filelist_contains(alpm_pkg_get_files(newpkg), +					fileobj->name)) { +			_alpm_log(handle, ALPM_LOG_DEBUG, +					"keeping directory %s (in new package)\n", file);  		} else {  			/* one last check- does any other package own this file? */  			alpm_list_t *local, *local_pkgs; @@ -285,7 +290,8 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,  				/* we duplicated the package when we put it in the removal list, so we  				 * so we can't use direct pointer comparison here. */ -				if(_alpm_pkg_cmp(info, local_pkg) == 0) { +				if(oldpkg->name_hash == local_pkg->name_hash +						&& strcmp(oldpkg->name, local_pkg->name) == 0) {  					continue;  				}  				filelist = alpm_pkg_get_files(local_pkg); @@ -308,7 +314,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,  		}  	} else {  		/* if the file needs backup and has been modified, back it up to .pacsave */ -		alpm_backup_t *backup = _alpm_needbackup(fileobj->name, info); +		alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg);  		if(backup) {  			if(nosave) {  				_alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); @@ -431,7 +437,7 @@ int _alpm_remove_single_package(alpm_handle_t *handle,  		alpm_file_t *file = filelist->files + i - 1;  		int percent;  		/* TODO: check return code and handle accordingly */ -		unlink_file(handle, oldpkg, file, skip_remove, +		unlink_file(handle, oldpkg, newpkg, file, skip_remove,  				handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE);  		if(!newpkg) { diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 92f34b56..0bef4451 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -270,6 +270,28 @@ static int key_search(alpm_handle_t *handle, const char *fpr,  	pgpkey->email = key->uids->email;  	pgpkey->created = key->subkeys->timestamp;  	pgpkey->expires = key->subkeys->expires; +	pgpkey->length = key->subkeys->length; +	pgpkey->revoked = key->subkeys->revoked; + +	switch (key->subkeys->pubkey_algo) { +		case GPGME_PK_RSA: +		case GPGME_PK_RSA_E: +		case GPGME_PK_RSA_S: +			pgpkey->pubkey_algo = 'R'; +			break; + +		case GPGME_PK_DSA: +			pgpkey->pubkey_algo = 'D'; +			break; + +		case GPGME_PK_ELG_E: +		case GPGME_PK_ELG: +		case GPGME_PK_ECDSA: +		case GPGME_PK_ECDH: +			pgpkey->pubkey_algo = 'E'; +			break; +	} +  	ret = 1;  error: diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index cf209717..3817ec84 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -423,7 +423,7 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)  		   see if they'd like to ignore them rather than failing the sync */  		if(unresolvable != NULL) {  			int remove_unresolvable = 0; -			enum _alpm_errno_t saved_err = handle->pm_errno; +			alpm_errno_t saved_err = handle->pm_errno;  			QUESTION(handle, ALPM_QUESTION_REMOVE_PKGS, unresolvable,  					NULL, NULL, &remove_unresolvable);  			if(remove_unresolvable) { @@ -695,11 +695,11 @@ static int apply_deltas(alpm_handle_t *handle)  			} else {  				/* len = cachedir len + from len + '/' + null */  				len = strlen(cachedir) + strlen(d->from) + 2; -				CALLOC(from, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); +				MALLOC(from, len, RET_ERR(handle, ALPM_ERR_MEMORY, 1));  				snprintf(from, len, "%s/%s", cachedir, d->from);  			}  			len = strlen(cachedir) + strlen(d->to) + 2; -			CALLOC(to, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); +			MALLOC(to, len, RET_ERR(handle, ALPM_ERR_MEMORY, 1));  			snprintf(to, len, "%s/%s", cachedir, d->to);  			/* build the patch command */ @@ -757,7 +757,7 @@ static int apply_deltas(alpm_handle_t *handle)   * @return 1 if file was removed, 0 otherwise   */  static int prompt_to_delete(alpm_handle_t *handle, const char *filepath, -		enum _alpm_errno_t reason) +		alpm_errno_t reason)  {  	int doremove = 0;  	QUESTION(handle, ALPM_QUESTION_CORRUPTED_PKG, (char *)filepath, @@ -803,11 +803,92 @@ static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas)  	return 0;  } +static struct dload_payload *build_payload(alpm_handle_t *handle, +		const char *filename, size_t size, alpm_list_t *servers) +{ +		struct dload_payload *payload; + +		CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); +		STRDUP(payload->remote_name, filename, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); +		payload->max_size = size; +		payload->servers = servers; +		return payload; +} + +static int find_dl_candidates(alpm_db_t *repo, alpm_list_t **files, alpm_list_t **deltas) +{ +	alpm_list_t *i; +	alpm_handle_t *handle = repo->handle; + +	for(i = handle->trans->add; i; i = i->next) { +		alpm_pkg_t *spkg = i->data; + +		if(spkg->origin != PKG_FROM_FILE && repo == spkg->origin_data.db) { +			alpm_list_t *delta_path = spkg->delta_path; + +			if(!repo->servers) { +				handle->pm_errno = ALPM_ERR_SERVER_NONE; +				_alpm_log(handle, ALPM_LOG_ERROR, "%s: %s\n", +						alpm_strerror(handle->pm_errno), repo->treename); +				return 1; +			} + +			if(delta_path) { +				/* using deltas */ +				alpm_list_t *dlts; +				for(dlts = delta_path; dlts; dlts = dlts->next) { +					alpm_delta_t *delta = dlts->data; +					if(delta->download_size != 0) { +						struct dload_payload *payload = build_payload( +								handle, delta->delta, delta->download_size, repo->servers); +						ASSERT(payload, return -1); +						*files = alpm_list_add(*files, payload); +					} +					/* keep a list of all the delta files for md5sums */ +					*deltas = alpm_list_add(*deltas, delta); +				} + +			} else if(spkg->download_size != 0) { +				struct dload_payload *payload; +				ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); +				payload = build_payload(handle, spkg->filename, spkg->size, repo->servers); +				ASSERT(payload, return -1); +				*files = alpm_list_add(*files, payload); +			} +		} +	} + +	return 0; +} + +static int download_single_file(alpm_handle_t *handle, struct dload_payload *payload, +		const char *cachedir) +{ +	const alpm_list_t *server; + +	for(server = payload->servers; server; server = server->next) { +		const char *server_url = server->data; +		size_t len; + +		/* print server + filename into a buffer */ +		len = strlen(server_url) + strlen(payload->remote_name) + 2; +		MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); +		snprintf(payload->fileurl, len, "%s/%s", server_url, payload->remote_name); +		payload->handle = handle; +		payload->allow_resume = 1; + +		if(_alpm_download(payload, cachedir, NULL) != -1) { +			return 0; +		} +	} + +	return -1; +} +  static int download_files(alpm_handle_t *handle, alpm_list_t **deltas)  {  	const char *cachedir; -	alpm_list_t *i, *j; -	alpm_list_t *files = NULL; +	alpm_list_t *i, *files = NULL;  	int errors = 0;  	cachedir = _alpm_filecache_setup(handle); @@ -826,91 +907,53 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas)  		handle->totaldlcb(total_size);  	} -	/* group sync records by repository and download */  	for(i = handle->dbs_sync; i; i = i->next) { -		alpm_db_t *current = i->data; - -		for(j = handle->trans->add; j; j = j->next) { -			alpm_pkg_t *spkg = j->data; - -			if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) { -				alpm_list_t *delta_path = spkg->delta_path; -				if(delta_path) { -					/* using deltas */ -					alpm_list_t *dlts; -					for(dlts = delta_path; dlts; dlts = dlts->next) { -						alpm_delta_t *delta = dlts->data; -						if(delta->download_size != 0) { -							struct dload_payload *dpayload; - -							CALLOC(dpayload, 1, sizeof(*dpayload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); -							STRDUP(dpayload->remote_name, delta->delta, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); -							dpayload->max_size = delta->download_size; - -							files = alpm_list_add(files, dpayload); -						} -						/* keep a list of all the delta files for md5sums */ -						*deltas = alpm_list_add(*deltas, delta); -					} +		errors += find_dl_candidates(i->data, &files, deltas); +	} -				} else if(spkg->download_size != 0) { -					struct dload_payload *payload; +	if(files) { +		/* check for necessary disk space for download */ +		if(handle->checkspace) { +			off_t *file_sizes; +			size_t idx, num_files; +			int ret; -					ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); -					CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); -					STRDUP(payload->remote_name, spkg->filename, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); -					payload->max_size = spkg->size; +			_alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space for download\n"); -					files = alpm_list_add(files, payload); -				} +			num_files = alpm_list_count(files); +			CALLOC(file_sizes, num_files, sizeof(off_t), goto finish); +			for(i = files, idx = 0; i; i = i->next, idx++) { +				const struct dload_payload *payload = i->data; +				file_sizes[idx] = payload->max_size;  			} -		} -		if(files) { -			if(!current->servers) { -				handle->pm_errno = ALPM_ERR_SERVER_NONE; -				_alpm_log(handle, ALPM_LOG_ERROR, "%s: %s\n", -						alpm_strerror(handle->pm_errno), current->treename); +			ret = _alpm_check_downloadspace(handle, cachedir, num_files, file_sizes); +			free(file_sizes); + +			if(ret != 0) {  				errors++; -				continue; +				goto finish;  			} +		} -			EVENT(handle, ALPM_EVENT_RETRIEVE_START, current->treename, NULL); -			for(j = files; j; j = j->next) { -				struct dload_payload *payload = j->data; -				alpm_list_t *server; -				int ret = -1; -				for(server = current->servers; server; server = server->next) { -					const char *server_url = server->data; -					size_t len; - -					/* print server + filename into a buffer */ -					len = strlen(server_url) + strlen(payload->remote_name) + 2; -					MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); -					snprintf(payload->fileurl, len, "%s/%s", server_url, payload->remote_name); -					payload->handle = handle; -					payload->allow_resume = 1; - -					ret = _alpm_download(payload, cachedir, NULL); -					if(ret != -1) { -						break; -					} -				} -				if(ret == -1) { -					errors++; -					_alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files from %s\n"), -							current->treename); -				} +		EVENT(handle, ALPM_EVENT_RETRIEVE_START, NULL, NULL); +		for(i = files; i; i = i->next) { +			if(download_single_file(handle, i->data, cachedir) == -1) { +				errors++; +				_alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files\n"));  			} - -			alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_reset); -			FREELIST(files);  		}  	} -	for(j = handle->trans->add; j; j = j->next) { -		alpm_pkg_t *pkg = j->data; +finish: +	if(files) { +		alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_reset); +		FREELIST(files); +	} + +	for(i = handle->trans->add; i; i = i->next) { +		alpm_pkg_t *pkg = i->data;  		pkg->infolevel &= ~INFRQ_DSIZE;  		pkg->download_size = 0;  	} @@ -931,7 +974,7 @@ static int check_validity(alpm_handle_t *handle,  		char *path;  		alpm_siglist_t *siglist;  		alpm_siglevel_t level; -		enum _alpm_errno_t error; +		alpm_errno_t error;  	};  	size_t current = 0, current_bytes = 0;  	alpm_list_t *i, *errors = NULL; diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index ad15d937..4eeb0cd7 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -24,22 +24,17 @@  #include "config.h" -#include <stdio.h>  #include <stdlib.h> -#include <stdarg.h> -#include <string.h>  #include <unistd.h>  #include <ctype.h>  #include <dirent.h> -#include <fcntl.h>  #include <time.h>  #include <syslog.h>  #include <errno.h>  #include <limits.h> -#include <sys/types.h> -#include <sys/stat.h>  #include <sys/wait.h>  #include <locale.h> /* setlocale */ +#include <fnmatch.h>  /* libarchive */  #include <archive.h> @@ -62,8 +57,16 @@  #include "trans.h"  #ifndef HAVE_STRSEP -/* This is a replacement for strsep which is not portable (missing on Solaris). - * Copyright (c) 2001 by François Gouget <fgouget_at_codeweavers.com> */ +/** Extracts tokens from a string. + * Replaces strset which is not portable (missing on Solaris). + * Copyright (c) 2001 by François Gouget <fgouget_at_codeweavers.com> + * Modifies str to point to the first character after the token if one is + * found, or NULL if one is not. + * @param str string containing delimited tokens to parse + * @param delim character delimiting tokens in str + * @return pointer to the first token in str if str is not NULL, NULL if + * str is NULL + */  char* strsep(char** str, const char* delims)  {  	char* token; @@ -93,7 +96,11 @@ int _alpm_makepath(const char *path)  	return _alpm_makepath_mode(path, 0755);  } -/* does the same thing as 'mkdir -p' */ +/** Creates a directory, including parents if needed, similar to 'mkdir -p'. + * @param path directory path to create + * @param mode permission mode for created directories + * @return 0 on success, 1 on error + */  int _alpm_makepath_mode(const char *path, mode_t mode)  {  	/* A bit of pointer hell here. Descriptions: @@ -129,55 +136,65 @@ int _alpm_makepath_mode(const char *path, mode_t mode)  	return ret;  } +/** Copies a file. + * @param src file path to copy from + * @param dest file path to copy to + * @return 0 on success, 1 on error  + */  int _alpm_copyfile(const char *src, const char *dest)  { -	FILE *in, *out; -	size_t len;  	char *buf; -	int ret = 0; +	int in, out, ret = 1; +	ssize_t nread; +	struct stat st; -	in = fopen(src, "rb"); -	if(in == NULL) { -		return 1; -	} -	out = fopen(dest, "wb"); -	if(out == NULL) { -		fclose(in); -		return 1; -	} +	MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); -	MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, ret = 1; goto cleanup); +	OPEN(in, src, O_RDONLY); +	do { +		out = open(dest, O_WRONLY | O_CREAT, 0000); +	} while(out == -1 && errno == EINTR); +	if(in < 0 || out < 0) { +		goto cleanup; +	} -	/* do the actual file copy */ -	while((len = fread(buf, 1, ALPM_BUFFER_SIZE, in))) { -		size_t nwritten = 0; -		nwritten = fwrite(buf, 1, len, out); -		if((nwritten != len) || ferror(out)) { -			ret = -1; -			goto cleanup; -		} +	if(fstat(in, &st) || fchmod(out, st.st_mode)) { +		goto cleanup;  	} -	/* chmod dest to permissions of src, as long as it is not a symlink */ -	struct stat statbuf; -	if(!stat(src, &statbuf)) { -		if(! S_ISLNK(statbuf.st_mode)) { -			fchmod(fileno(out), statbuf.st_mode); +	/* do the actual file copy */ +	while((nread = read(in, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { +		ssize_t nwrite = 0; +		if(nread < 0) { +			continue;  		} -	} else { -		/* stat was unsuccessful */ -		ret = 1; +		do { +			nwrite = write(out, buf + nwrite, nread); +			if(nwrite >= 0) { +				nread -= nwrite; +			} else if(errno != EINTR) { +				goto cleanup; +			} +		} while(nread > 0);  	} +	ret = 0;  cleanup: -	fclose(in); -	fclose(out);  	free(buf); +	if(in >= 0) { +		CLOSE(in); +	} +	if(out >= 0) { +		CLOSE(out); +	}  	return ret;  } -/* Trim whitespace and newlines from a string -*/ +/** Trim leading and trailing whitespace, including newlines, from a string. + * Modifies str in place. + * @param str a string to trim + * @return str + */  char *_alpm_strtrim(char *str)  {  	char *pch = str; @@ -193,6 +210,7 @@ char *_alpm_strtrim(char *str)  	if(pch != str) {  		size_t len = strlen(pch);  		if(len) { +			/* move the remaining string to the beginning of str */  			memmove(str, pch, len + 1);  		} else {  			*str = '\0'; @@ -213,8 +231,7 @@ char *_alpm_strtrim(char *str)  	return str;  } -/** - * Trim trailing newline from a string (if one exists). +/** Trim trailing newlines from a string (if any exist).   * @param str a single line of text   * @return the length of the trimmed string   */ @@ -235,9 +252,64 @@ size_t _alpm_strip_newline(char *str)  /* Compression functions */ -/** - * @brief Unpack a specific file in an archive. - * +/** Open an archive for reading and perform the necessary boilerplate. + * This takes care of creating the libarchive 'archive' struct, setting up + * compression and format options, opening a file descriptor, setting up the + * buffer size, and performing a stat on the path once opened. + * @param handle the context handle + * @param path the path of the archive to open + * @param buf space for a stat buffer for the given path + * @param archive pointer to place the created archive object + * @param error error code to set on failure to open archive + * @return -1 on failure, >=0 file descriptor on success + */ +int _alpm_open_archive(alpm_handle_t *handle, const char *path, +		struct stat *buf, struct archive **archive, alpm_errno_t error) +{ +	int fd; +	size_t bufsize = ALPM_BUFFER_SIZE; + +	if((*archive = archive_read_new()) == NULL) { +		RET_ERR(handle, ALPM_ERR_LIBARCHIVE, -1); +	} + +	archive_read_support_compression_all(*archive); +	archive_read_support_format_all(*archive); + +	_alpm_log(handle, ALPM_LOG_DEBUG, "opening archive %s\n", path); +	OPEN(fd, path, O_RDONLY); +	if(fd < 0) { +		_alpm_log(handle, ALPM_LOG_ERROR, +				_("could not open file %s: %s\n"), path, strerror(errno)); +		archive_read_finish(*archive); +		RET_ERR(handle, error, -1); +	} + +	if(fstat(fd, buf) != 0) { +		_alpm_log(handle, ALPM_LOG_ERROR, +				_("could not stat file %s: %s\n"), path, strerror(errno)); +		archive_read_finish(*archive); +		CLOSE(fd); +		RET_ERR(handle, error, -1); +	} +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE +	if(buf->st_blksize > ALPM_BUFFER_SIZE) { +		bufsize = buf->st_blksize; +	} +#endif + +	if(archive_read_open_fd(*archive, fd, bufsize) != ARCHIVE_OK) { +		_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), +				path, archive_error_string(*archive)); +		archive_read_finish(*archive); +		CLOSE(fd); +		RET_ERR(handle, error, -1); +	} + +	return fd; +} + +/** Unpack a specific file in an archive.   * @param handle the context handle   * @param archive the archive to unpack   * @param prefix where to extract the files @@ -258,46 +330,33 @@ int _alpm_unpack_single(alpm_handle_t *handle, const char *archive,  	return ret;  } -/** - * @brief Unpack a list of files in an archive. - * +/** Unpack a list of files in an archive.   * @param handle the context handle - * @param archive the archive to unpack + * @param path the archive to unpack   * @param prefix where to extract the files   * @param list a list of files within the archive to unpack or NULL for all   * @param breakfirst break after the first entry found - *   * @return 0 on success, 1 on failure   */ -int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, +int _alpm_unpack(alpm_handle_t *handle, const char *path, const char *prefix,  		alpm_list_t *list, int breakfirst)  {  	int ret = 0;  	mode_t oldmask; -	struct archive *_archive; +	struct archive *archive;  	struct archive_entry *entry; -	int cwdfd; - -	if((_archive = archive_read_new()) == NULL) { -		RET_ERR(handle, ALPM_ERR_LIBARCHIVE, 1); -	} - -	archive_read_support_compression_all(_archive); -	archive_read_support_format_all(_archive); +	struct stat buf; +	int fd, cwdfd; -	if(archive_read_open_filename(_archive, archive, -				ALPM_BUFFER_SIZE) != ARCHIVE_OK) { -		_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), archive, -				archive_error_string(_archive)); -		RET_ERR(handle, ALPM_ERR_PKG_OPEN, 1); +	fd = _alpm_open_archive(handle, path, &buf, &archive, ALPM_ERR_PKG_OPEN); +	if(fd < 0) { +		return 1;  	}  	oldmask = umask(0022);  	/* save the cwd so we can restore it later */ -	do { -		cwdfd = open(".", O_RDONLY); -	} while(cwdfd == -1 && errno == EINTR); +	OPEN(cwdfd, ".", O_RDONLY);  	if(cwdfd < 0) {  		_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));  	} @@ -310,19 +369,12 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  		goto cleanup;  	} -	while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { -		const struct stat *st; -		const char *entryname; /* the name of the file in the archive */ +	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { +		const char *entryname; +		mode_t mode; -		st = archive_entry_stat(entry);  		entryname = archive_entry_pathname(entry); -		if(S_ISREG(st->st_mode)) { -			archive_entry_set_perm(entry, 0644); -		} else if(S_ISDIR(st->st_mode)) { -			archive_entry_set_perm(entry, 0755); -		} -  		/* If specific files were requested, skip entries that don't match. */  		if(list) {  			char *entry_prefix = strdup(entryname); @@ -333,7 +385,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  			char *found = alpm_list_find_str(list, entry_prefix);  			free(entry_prefix);  			if(!found) { -				if(archive_read_data_skip(_archive) != ARCHIVE_OK) { +				if(archive_read_data_skip(archive) != ARCHIVE_OK) {  					ret = 1;  					goto cleanup;  				} @@ -343,15 +395,22 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  			}  		} +		mode = archive_entry_mode(entry); +		if(S_ISREG(mode)) { +			archive_entry_set_perm(entry, 0644); +		} else if(S_ISDIR(mode)) { +			archive_entry_set_perm(entry, 0755); +		} +  		/* Extract the archive entry. */ -		int readret = archive_read_extract(_archive, entry, 0); +		int readret = archive_read_extract(archive, entry, 0);  		if(readret == ARCHIVE_WARN) {  			/* operation succeeded but a non-critical error was encountered */  			_alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"), -					entryname, archive_error_string(_archive)); +					entryname, archive_error_string(archive));  		} else if(readret != ARCHIVE_OK) {  			_alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"), -					entryname, archive_error_string(_archive)); +					entryname, archive_error_string(archive));  			ret = 1;  			goto cleanup;  		} @@ -363,19 +422,23 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  cleanup:  	umask(oldmask); -	archive_read_finish(_archive); +	archive_read_finish(archive); +	CLOSE(fd);  	if(cwdfd >= 0) {  		if(fchdir(cwdfd) != 0) {  			_alpm_log(handle, ALPM_LOG_ERROR,  					_("could not restore working directory (%s)\n"), strerror(errno));  		} -		close(cwdfd); +		CLOSE(cwdfd);  	}  	return ret;  } -/* does the same thing as 'rm -rf' */ +/** Recursively removes a path similar to 'rm -rf'. + * @param path path to remove + * @return 0 on success, number of paths that could not be removed on error + */  int _alpm_rmrf(const char *path)  {  	int errflag = 0; @@ -418,8 +481,7 @@ int _alpm_rmrf(const char *path)  	return 0;  } -/** - * Determine if there are files in a directory +/** Determine if there are files in a directory.   * @param handle the context handle   * @param path the full absolute directory path   * @param full_count whether to return an exact count of files @@ -460,6 +522,13 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path,  	return files;  } +/** Write formatted message to log. + * @param handle the context handle + * @param format formatted string to write out + * @param args formatting arguments + * @return 0 or number of characters written on success, vfprintf return value + * on error + */  int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args)  {  	int ret = 0; @@ -491,16 +560,20 @@ int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args)  	return ret;  } -int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]) +/** Execute a command with arguments in a chroot. + * @param handle the context handle + * @param cmd command to execute + * @param argv arguments to pass to cmd + * @return 0 on success, 1 on error + */ +int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])  {  	pid_t pid;  	int pipefd[2], cwdfd;  	int retval = 0;  	/* save the cwd so we can restore it later */ -	do { -		cwdfd = open(".", O_RDONLY); -	} while(cwdfd == -1 && errno == EINTR); +	OPEN(cwdfd, ".", O_RDONLY);  	if(cwdfd < 0) {  		_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));  	} @@ -513,7 +586,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]  	}  	_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", -			path, handle->root); +			cmd, handle->root);  	/* Flush open fds before fork() to avoid cloning buffers */  	fflush(NULL); @@ -534,12 +607,12 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]  	if(pid == 0) {  		/* this code runs for the child only (the actual chroot/exec) */ -		close(1); -		close(2); +		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]); +		CLOSE(pipefd[0]); +		CLOSE(pipefd[1]);  		/* use fprintf instead of _alpm_log to send output through the parent */  		if(chroot(handle->root) != 0) { @@ -552,7 +625,8 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]  			exit(1);  		}  		umask(0022); -		execv(path, argv); +		execv(cmd, argv); +		/* execv only returns if there was an error */  		fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno));  		exit(1);  	} else { @@ -560,10 +634,10 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]  		int status;  		FILE *pipe_file; -		close(pipefd[1]); +		CLOSE(pipefd[1]);  		pipe_file = fdopen(pipefd[0], "r");  		if(pipe_file == NULL) { -			close(pipefd[0]); +			CLOSE(pipefd[0]);  			retval = 1;  		} else {  			while(!feof(pipe_file)) { @@ -605,12 +679,16 @@ cleanup:  			_alpm_log(handle, ALPM_LOG_ERROR,  					_("could not restore working directory (%s)\n"), strerror(errno));  		} -		close(cwdfd); +		CLOSE(cwdfd);  	}  	return retval;  } +/** Run ldconfig in a chroot. + * @param handle the context handle + * @return 0 on success, 1 on error + */  int _alpm_ldconfig(alpm_handle_t *handle)  {  	char line[PATH_MAX]; @@ -629,8 +707,13 @@ int _alpm_ldconfig(alpm_handle_t *handle)  	return 0;  } -/* Helper function for comparing strings using the - * alpm "compare func" signature */ +/** Helper function for comparing strings using the alpm "compare func" + * signature. + * @param s1 first string to be compared + * @param s2 second string to be compared + * @return 0 if strings are equal, positive int if first unequal character + * has a greater value in s1, negative if it has a greater value in s2 + */  int _alpm_str_cmp(const void *s1, const void *s2)  {  	return strcmp(s1, s2); @@ -739,51 +822,64 @@ int _alpm_lstat(const char *path, struct stat *buf)  }  #ifdef HAVE_LIBSSL +/** Compute the MD5 message digest of a file. + * @param path file path of file to compute  MD5 digest of + * @param output string to hold computed MD5 digest + * @return 0 on success, 1 on file open error, 2 on file read error + */  static int md5_file(const char *path, unsigned char output[16])  { -	FILE *f; -	size_t n;  	MD5_CTX ctx;  	unsigned char *buf; +	ssize_t n; +	int fd; -	CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); +	MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); -	if((f = fopen(path, "rb")) == NULL) { +	OPEN(fd, path, O_RDONLY); +	if(fd < 0) {  		free(buf);  		return 1;  	}  	MD5_Init(&ctx); -	while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { +	while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { +		if(n < 0) { +			continue; +		}  		MD5_Update(&ctx, buf, n);  	} -	MD5_Final(output, &ctx); - -	memset(&ctx, 0, sizeof(MD5_CTX)); +	CLOSE(fd);  	free(buf); -	if(ferror(f) != 0) { -		fclose(f); +	if(n < 0) {  		return 2;  	} -	fclose(f); +	MD5_Final(output, &ctx);  	return 0;  }  /* third param is so we match the PolarSSL definition */ +/** Compute the SHA-224 or SHA-256 message digest of a file. + * @param path file path of file to compute SHA2 digest of + * @param output string to hold computed SHA2 digest + * @param is224 use SHA-224 instead of SHA-256 + * @return 0 on success, 1 on file open error, 2 on file read error + */  static int sha2_file(const char *path, unsigned char output[32], int is224)  { -	FILE *f; -	size_t n;  	SHA256_CTX ctx;  	unsigned char *buf; +	ssize_t n; +	int fd; -	CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); +	MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); -	if((f = fopen(path, "rb")) == NULL) { +	OPEN(fd, path, O_RDONLY); +	if(fd < 0) {  		free(buf);  		return 1;  	} @@ -794,7 +890,10 @@ static int sha2_file(const char *path, unsigned char output[32], int is224)  		SHA256_Init(&ctx);  	} -	while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { +	while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { +		if(n < 0) { +			continue; +		}  		if(is224) {  			SHA224_Update(&ctx, buf, n);  		} else { @@ -802,25 +901,24 @@ static int sha2_file(const char *path, unsigned char output[32], int is224)  		}  	} -	if(is224) { -		SHA224_Final(output, &ctx); -	} else { -		SHA256_Final(output, &ctx); -	} - -	memset(&ctx, 0, sizeof(SHA256_CTX)); +	CLOSE(fd);  	free(buf); -	if(ferror(f) != 0) { -		fclose(f); +	if(n < 0) {  		return 2;  	} -	fclose(f); +	if(is224) { +		SHA224_Final(output, &ctx); +	} else { +		SHA256_Final(output, &ctx); +	}  	return 0;  }  #endif +static const char *hex_digits = "0123456789abcdef"; +  /** Get the md5 sum of file.   * @param filename name of the file   * @return the checksum on success, NULL on error @@ -834,8 +932,7 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename)  	ASSERT(filename != NULL, return NULL); -	/* allocate 32 chars plus 1 for null */ -	CALLOC(md5sum, 33, sizeof(char), return NULL); +	MALLOC(md5sum, (size_t)33, return NULL);  	/* defined above for OpenSSL, otherwise defined in md5.h */  	ret = md5_file(filename, output); @@ -845,11 +942,13 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename)  	}  	/* Convert the result to something readable */ -	for (i = 0; i < 16; i++) { -		/* sprintf is acceptable here because we know our output */ -		sprintf(md5sum +(i * 2), "%02x", output[i]); +	for(i = 0; i < 16; i++) { +		int pos = i * 2; +		/* high 4 bits are first digit, low 4 are second */ +		md5sum[pos] = hex_digits[output[i] >> 4]; +		md5sum[pos + 1] = hex_digits[output[i] & 0x0f];  	} - +	md5sum[32] = '\0';  	return md5sum;  } @@ -866,8 +965,7 @@ char SYMEXPORT *alpm_compute_sha256sum(const char *filename)  	ASSERT(filename != NULL, return NULL); -	/* allocate 64 chars plus 1 for null */ -	CALLOC(sha256sum, 65, sizeof(char), return NULL); +	MALLOC(sha256sum, (size_t)65, return NULL);  	/* defined above for OpenSSL, otherwise defined in sha2.h */  	ret = sha2_file(filename, output, 0); @@ -877,14 +975,23 @@ char SYMEXPORT *alpm_compute_sha256sum(const char *filename)  	}  	/* Convert the result to something readable */ -	for (i = 0; i < 32; i++) { -		/* sprintf is acceptable here because we know our output */ -		sprintf(sha256sum +(i * 2), "%02x", output[i]); +	for(i = 0; i < 32; i++) { +		int pos = i * 2; +		/* high 4 bits are first digit, low 4 are second */ +		sha256sum[pos] = hex_digits[output[i] >> 4]; +		sha256sum[pos + 1] = hex_digits[output[i] & 0x0f];  	} - +	sha256sum[64] = '\0';  	return sha256sum;  } +/** Calculates a file's MD5 or SHA2 digest  and compares it to an expected value.  + * @param filepath path of the file to check + * @param expected hash value to compare against + * @param type digest type to use + * @return 0 if file matches the expected hash, 1 if they do not match, -1 on + * error + */  int _alpm_test_checksum(const char *filepath, const char *expected,  		enum _alpm_csum type)  { @@ -912,18 +1019,24 @@ int _alpm_test_checksum(const char *filepath, const char *expected,  }  /* Note: does NOT handle sparse files on purpose for speed. */ +/** TODO. + * Does not handle sparse files on purpose for speed. + * @param a + * @param b + * @return  + */  int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)  { -	char *i = NULL; -	int64_t offset; -	int done = 0; -  	/* ensure we start populating our line buffer at the beginning */  	b->line_offset = b->line;  	while(1) { +		size_t block_remaining; +		char *eol; +  		/* have we processed this entire block? */  		if(b->block + b->block_size == b->block_offset) { +			int64_t offset;  			if(b->ret == ARCHIVE_EOF) {  				/* reached end of archive on the last read, now we are out of data */  				goto cleanup; @@ -933,20 +1046,20 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)  			b->ret = archive_read_data_block(a, (void *)&b->block,  					&b->block_size, &offset);  			b->block_offset = b->block; +			block_remaining = b->block_size;  			/* error, cleanup */  			if(b->ret < ARCHIVE_OK) {  				goto cleanup;  			} +		} else { +			block_remaining = b->block + b->block_size - b->block_offset;  		} -		/* 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; -			} +		/* look through the block looking for EOL characters */ +		eol = memchr(b->block_offset, '\n', block_remaining); +		if(!eol) { +			eol = memchr(b->block_offset, '\0', block_remaining);  		}  		/* allocate our buffer, or ensure our existing one is big enough */ @@ -956,8 +1069,10 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)  			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); +			/* note: we know eol > b->block_offset and b->line_offset > b->line, +			 * so we know the result is unsigned and can fit in size_t */ +			size_t new = eol ? (size_t)(eol - b->block_offset) : block_remaining; +			size_t needed = (size_t)((b->line_offset - b->line) + new + 1);  			if(needed > b->max_line_size) {  				b->ret = -ERANGE;  				goto cleanup; @@ -974,11 +1089,11 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)  			}  		} -		if(done) { -			size_t len = (size_t)(i - b->block_offset); +		if(eol) { +			size_t len = (size_t)(eol - b->block_offset);  			memcpy(b->line_offset, b->block_offset, len);  			b->line_offset[len] = '\0'; -			b->block_offset = ++i; +			b->block_offset = eol + 1;  			/* this is the main return point; from here you can read b->line */  			return ARCHIVE_OK;  		} else { @@ -986,7 +1101,7 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)  			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; +			b->block_offset = b->block + b->block_size;  			/* there was no new data, return what is left; saved ARCHIVE_EOF will be  			 * returned on next call */  			if(len == 0) { @@ -1005,6 +1120,14 @@ cleanup:  	}  } +/** Parse a full package specifier. + * @param target package specifier to parse, such as: "pacman-4.0.1-2", + * "pacman-4.01-2/", or "pacman-4.0.1-2/desc" + * @param name to hold package name + * @param version to hold package version + * @param name_hash to hold package name hash + * @return 0 on success, -1 on error + */  int _alpm_splitname(const char *target, char **name, char **version,  		unsigned long *name_hash)  { @@ -1057,8 +1180,7 @@ int _alpm_splitname(const char *target, char **name, char **version,  	return 0;  } -/** - * Hash the given string to an unsigned long value. +/** 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 @@ -1078,6 +1200,11 @@ unsigned long _alpm_hash_sdbm(const char *str)  	return hash;  } +/** Convert a string to a file offset. + * This parses bare positive integers only. + * @param line string to convert + * @return off_t on success, -1 on error + */  off_t _alpm_strtoofft(const char *line)  {  	char *end; @@ -1089,13 +1216,13 @@ off_t _alpm_strtoofft(const char *line)  		return (off_t)-1;  	}  	result = strtoull(line, &end, 10); -	if (result == 0 && end == line) { +	if(result == 0 && end == line) {  		/* line was not a number */  		return (off_t)-1; -	} else if (result == ULLONG_MAX && errno == ERANGE) { +	} else if(result == ULLONG_MAX && errno == ERANGE) {  		/* line does not fit in unsigned long long */  		return (off_t)-1; -	} else if (*end) { +	} else if(*end) {  		/* line began with a number but has junk left over at the end */  		return (off_t)-1;  	} @@ -1103,8 +1230,16 @@ off_t _alpm_strtoofft(const char *line)  	return (off_t)result;  } -time_t _alpm_parsedate(const char *line) +/** Parses a date into an alpm_time_t struct. + * @param line date to parse + * @return time struct on success, 0 on error + */ +alpm_time_t _alpm_parsedate(const char *line)  { +	char *end; +	long long result; +	errno = 0; +  	if(isalpha((unsigned char)line[0])) {  		/* initialize to null in case of failure */  		struct tm tmp_tm; @@ -1112,13 +1247,27 @@ time_t _alpm_parsedate(const char *line)  		setlocale(LC_TIME, "C");  		strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);  		setlocale(LC_TIME, ""); -		return mktime(&tmp_tm); +		return (alpm_time_t)mktime(&tmp_tm);  	} -	return (time_t)atol(line); + +	result = strtoll(line, &end, 10); +	if(result == 0 && end == line) { +		/* line was not a number */ +		errno = EINVAL; +		return 0; +	} else if(errno == ERANGE) { +		/* line does not fit in long long */ +		return 0; +	} else if(*end) { +		/* line began with a number but has junk left over at the end */ +		errno = EINVAL; +		return 0; +	} + +	return (alpm_time_t)result;  } -/** - * Wrapper around access() which takes a dir and file argument +/** Wrapper around access() which takes a dir and file argument   * separately and generates an appropriate error message.   * If dir is NULL file will be treated as the whole path.   * @param handle an alpm handle @@ -1127,13 +1276,12 @@ time_t _alpm_parsedate(const char *line)   * @param amode access mode as described in access()   * @return int value returned by access()   */ -  int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int amode)  {  	size_t len = 0;  	int ret = 0; -	if (dir) { +	if(dir) {  		char *check_path;  		len = strlen(dir) + strlen(file) + 1; @@ -1148,19 +1296,19 @@ int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int a  	}  	if(ret != 0) { -		if (amode & R_OK) { +		if(amode & R_OK) {  			_alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not readable: %s\n",  					dir, file, strerror(errno));  		} -		if (amode & W_OK) { +		if(amode & W_OK) {  			_alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not writable: %s\n",  					dir, file, strerror(errno));  		} -		if (amode & X_OK) { +		if(amode & X_OK) {  			_alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not executable: %s\n",  					dir, file, strerror(errno));  		} -		if (amode == F_OK) { +		if(amode == F_OK) {  			_alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" does not exist: %s\n",  					dir, file, strerror(errno));  		} @@ -1168,8 +1316,25 @@ int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int a  	return ret;  } +/** Checks whether a string matches a shell wildcard pattern. + * Wrapper around fnmatch. + * @param pattern pattern to match aganist + * @param string string to check against pattern + * @return 0 if string matches pattern, non-zero if they don't match and on + * error + */ +int _alpm_fnmatch(const void *pattern, const void *string) +{ +	return fnmatch(pattern, string, 0); +} +  #ifndef HAVE_STRNDUP  /* A quick and dirty implementation derived from glibc */ +/** Determines the length of a fixed-size string. + * @param s string to be measured + * @param max maximum number of characters to search for the string end + * @return length of s or max, whichever is smaller + */  static size_t strnlen(const char *s, size_t max)  {      register const char *p; @@ -1177,6 +1342,12 @@ static size_t strnlen(const char *s, size_t max)      return (p - s);  } +/** Copies a string. + * Returned string needs to be freed + * @param s string to be copied + * @param n maximum number of characters to copy + * @return pointer to the new string on success, NULL on error + */  char *strndup(const char *s, size_t n)  {    size_t len = strnlen(s, n); diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 26fa9044..1e192747 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -35,11 +35,13 @@  #include <string.h>  #include <stdarg.h>  #include <stddef.h> /* size_t */ -#include <time.h> +#include <sys/types.h>  #include <sys/stat.h> /* struct stat */ -#include <archive.h> /* struct archive */  #include <math.h> /* fabs */  #include <float.h> /* DBL_EPSILON */ +#include <fcntl.h> /* open, close */ + +#include <archive.h> /* struct archive */  #ifdef ENABLE_NLS  #include <libintl.h> /* here so it doesn't need to be included elsewhere */ @@ -51,8 +53,8 @@  #define ALLOC_FAIL(s) do { fprintf(stderr, "alloc failure: could not allocate %zd bytes\n", s); } while(0) -#define MALLOC(p, s, action) do { p = calloc(1, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) -#define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) +#define MALLOC(p, s, action) do { p = malloc(s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) +#define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(l * 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) @@ -82,6 +84,13 @@  #define ALPM_BUFFER_SIZE 8192  #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define OPEN(fd, path, flags) do { fd = open(path, flags | O_BINARY); } while(fd == -1 && errno == EINTR) +#define CLOSE(fd) do { int ret; do { ret = close(fd); } while(ret == -1 && errno == EINTR); } while(0) +  /**   * Used as a buffer/state holder for _alpm_archive_fgets().   */ @@ -108,6 +117,9 @@ int _alpm_makepath_mode(const char *path, mode_t mode);  int _alpm_copyfile(const char *src, const char *dest);  char *_alpm_strtrim(char *str);  size_t _alpm_strip_newline(char *str); + +int _alpm_open_archive(alpm_handle_t *handle, const char *path, +		struct stat *buf, struct archive **archive, alpm_errno_t error);  int _alpm_unpack_single(alpm_handle_t *handle, const char *archive,  		const char *prefix, const char *filename);  int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, @@ -115,7 +127,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  int _alpm_rmrf(const char *path);  ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int full_count);  int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args); -int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]); +int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[]);  int _alpm_ldconfig(alpm_handle_t *handle);  int _alpm_str_cmp(const void *s1, const void *s2);  char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename); @@ -127,10 +139,11 @@ int _alpm_splitname(const char *target, char **name, char **version,  		unsigned long *name_hash);  unsigned long _alpm_hash_sdbm(const char *str);  off_t _alpm_strtoofft(const char *line); -time_t _alpm_parsedate(const char *line); +alpm_time_t _alpm_parsedate(const char *line);  int _alpm_raw_cmp(const char *first, const char *second);  int _alpm_raw_ncmp(const char *first, const char *second, size_t max);  int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int amode); +int _alpm_fnmatch(const void *pattern, const void *string);  #ifndef HAVE_STRSEP  char *strsep(char **, const char *); | 
