diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/libalpm/add.c | 98 | ||||
| -rw-r--r-- | lib/libalpm/alpm.h | 16 | ||||
| -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 | 9 | ||||
| -rw-r--r-- | lib/libalpm/be_package.c | 50 | ||||
| -rw-r--r-- | lib/libalpm/be_sync.c | 54 | ||||
| -rw-r--r-- | lib/libalpm/conflict.c | 10 | ||||
| -rw-r--r-- | lib/libalpm/db.h | 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/package.c | 10 | ||||
| -rw-r--r-- | lib/libalpm/package.h | 9 | ||||
| -rw-r--r-- | lib/libalpm/remove.c | 16 | ||||
| -rw-r--r-- | lib/libalpm/sync.c | 193 | ||||
| -rw-r--r-- | lib/libalpm/util.c | 252 | ||||
| -rw-r--r-- | lib/libalpm/util.h | 19 | 
21 files changed, 511 insertions, 356 deletions
| diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 6c2f0cb6..d66ab934 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", @@ -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;  } @@ -543,9 +547,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,  		}  		/* 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"));  		} @@ -602,7 +604,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.h b/lib/libalpm/alpm.h index a93d4e3e..9fda9406 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,8 @@ 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;  } alpm_pgpkey_t;  /** Signature result. Contains the key, status, and validity of a given @@ -754,13 +756,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 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..21d27481 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; @@ -794,11 +793,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..90a19722 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> @@ -355,7 +358,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,34 +370,41 @@ 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); -		} -		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);  	}  	archive_read_support_compression_all(archive);  	archive_read_support_format_all(archive); -	if(archive_read_open_filename(archive, pkgfile, +	OPEN(fd, pkgfile, O_RDONLY); +	if(fd < 0 || archive_read_open_fd(archive, fd,  				ALPM_BUFFER_SIZE) != ARCHIVE_OK) { -		alpm_pkg_free(newpkg); -		RET_ERR(handle, ALPM_ERR_PKG_OPEN, NULL); +		const char *err = fd < 0 ? strerror(errno) : archive_error_string(archive); +		_alpm_log(handle, ALPM_LOG_ERROR, +				_("could not open file %s: %s\n"), pkgfile, err); +		if(fd < 0 && errno == ENOENT) { +			handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND; +		} else { +			handle->pm_errno = ALPM_ERR_PKG_OPEN; +		} +		goto error;  	} +	newpkg = _alpm_pkg_new(); +	if(newpkg == NULL) { +		handle->pm_errno = ALPM_ERR_MEMORY; +		goto error; +	} +	if(fstat(fd, &st) != 0) { +		handle->pm_errno = ALPM_ERR_PKG_OPEN; +		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);  	/* If full is false, only read through the archive until we find our needed @@ -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..aa260020 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,6 +427,11 @@ 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);  	} +	dbpath = _alpm_db_path(db); +	if(!dbpath) { +		/* pm_errno set in _alpm_db_path() */ +		return -1; +	}  	if((archive = archive_read_new()) == NULL) {  		RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1); @@ -431,30 +440,28 @@ static int sync_db_populate(alpm_db_t *db)  	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_log(db->handle, ALPM_LOG_DEBUG, +			"opening database archive %s\n", dbpath); +	OPEN(fd, dbpath, O_RDONLY); +	if(fd < 0 || archive_read_open_fd(archive, fd,  				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); +		const char *err = fd < 0 ? strerror(errno) : archive_error_string(archive); +		_alpm_log(db->handle, ALPM_LOG_ERROR, +				_("could not open file %s: %s\n"), dbpath, err); +		db->handle->pm_errno = ALPM_ERR_DB_OPEN; +		goto cleanup;  	} -	if(stat(dbpath, &buf) != 0) { -		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); +	if(fstat(fd, &buf) != 0) { +		db->handle->pm_errno = ALPM_ERR_DB_OPEN; +		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 +480,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..486f4bf3 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;  } 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/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 efd469d5..76bb00f9 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/package.c b/lib/libalpm/package.c index a5ff238f..0b0bf6e4 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; 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..cf137ae8 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -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]; @@ -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/sync.c b/lib/libalpm/sync.c index 54b9794a..52049a8c 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -686,11 +686,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 */ @@ -794,11 +794,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); @@ -817,91 +898,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;  	} diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index fbb320ef..cbc5bdfb 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -24,20 +24,14 @@  #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 */ @@ -131,48 +125,50 @@ int _alpm_makepath_mode(const char *path, mode_t mode)  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;  } @@ -295,9 +291,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  	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"));  	} @@ -311,18 +305,11 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,  	}  	while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { -		const struct stat *st; -		const char *entryname; /* the name of the file in the archive */ +		const char *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); @@ -343,6 +330,13 @@ 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);  		if(readret == ARCHIVE_WARN) { @@ -369,7 +363,7 @@ cleanup:  			_alpm_log(handle, ALPM_LOG_ERROR,  					_("could not restore working directory (%s)\n"), strerror(errno));  		} -		close(cwdfd); +		CLOSE(cwdfd);  	}  	return ret; @@ -498,9 +492,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]  	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"));  	} @@ -534,12 +526,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) { @@ -553,6 +545,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]  		}  		umask(0022);  		execv(path, argv); +		/* execv only returns if there was an error */  		fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno));  		exit(1);  	} else { @@ -560,10 +553,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,7 +598,7 @@ cleanup:  			_alpm_log(handle, ALPM_LOG_ERROR,  					_("could not restore working directory (%s)\n"), strerror(errno));  		} -		close(cwdfd); +		CLOSE(cwdfd);  	}  	return retval; @@ -741,49 +734,51 @@ int _alpm_lstat(const char *path, struct stat *buf)  #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; +	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 */  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 +789,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 +800,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 +831,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); @@ -846,10 +842,12 @@ 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]); +		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 +864,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); @@ -878,10 +875,12 @@ 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]); +		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;  } @@ -914,16 +913,16 @@ int _alpm_test_checksum(const char *filepath, const char *expected,  /* Note: does NOT handle sparse files on purpose for speed. */  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 +932,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 +955,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 +975,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 +987,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) { @@ -1103,8 +1104,12 @@ off_t _alpm_strtoofft(const char *line)  	return (off_t)result;  } -time_t _alpm_parsedate(const char *line) +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,9 +1117,24 @@ 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;  }  /** diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 26fa9044..61dc8e55 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().   */ @@ -127,7 +136,7 @@ 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); | 
