diff options
Diffstat (limited to 'lib')
-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 | 9 | ||||
-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 | 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/error.c | 4 | ||||
-rw-r--r-- | lib/libalpm/handle.c | 2 | ||||
-rw-r--r-- | lib/libalpm/handle.h | 4 | ||||
-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 | 501 | ||||
-rw-r--r-- | lib/libalpm/util.h | 25 |
26 files changed, 809 insertions, 493 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..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..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..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 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..d568fb42 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -93,7 +93,7 @@ struct __alpm_handle_t { 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..96e1ef66 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); @@ -846,10 +943,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 +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); @@ -878,13 +976,22 @@ 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; } +/** 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; @@ -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); + } + + 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 (time_t)atol(line); + + 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,7 +1276,6 @@ 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; @@ -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 *); |