diff options
Diffstat (limited to 'lib')
38 files changed, 935 insertions, 700 deletions
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 99f9c1b7..61dcb877 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -7,6 +7,9 @@ include_HEADERS = alpm_list.h alpm.h DEFS = -DLOCALEDIR=\"@localedir@\" @DEFS@ +AM_CPPFLAGS = \ + -imacros $(top_builddir)/config.h + AM_CFLAGS = -pedantic -D_GNU_SOURCE if ENABLE_VISIBILITY_CC diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 6c2f0cb6..014990d2 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -18,11 +18,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <errno.h> -#include <time.h> #include <string.h> #include <limits.h> #include <fcntl.h> @@ -132,6 +129,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 +155,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 +177,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 +257,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 +289,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 +328,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 +361,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 +383,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 +425,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 +446,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 +523,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 +545,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 +588,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 +596,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..3f7ab4ba 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #ifdef HAVE_LIBCURL #include <curl/curl.h> #endif @@ -47,9 +45,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/backup.c b/lib/libalpm/backup.c index 728c1d05..68856deb 100644 --- a/lib/libalpm/backup.c +++ b/lib/libalpm/backup.c @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> 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..2deef22c 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -28,7 +26,6 @@ #include <stdint.h> /* intmax_t */ #include <sys/stat.h> #include <dirent.h> -#include <time.h> #include <limits.h> /* PATH_MAX */ /* libalpm */ @@ -69,13 +66,13 @@ static const char *_cache_get_url(alpm_pkg_t *pkg) return pkg->url; } -static time_t _cache_get_builddate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_builddate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, 0); return pkg->builddate; } -static time_t _cache_get_installdate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_installdate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, 0); return pkg->installdate; @@ -475,7 +472,8 @@ static int local_db_populate(alpm_db_t *db) } /* Note: the return value must be freed by the caller */ -char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filename) +char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, + const char *filename) { size_t len; char *pkgpath; @@ -638,10 +636,11 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) while(fgets(line, sizeof(line), fp)) { _alpm_strip_newline(line); if(strcmp(line, "%FILES%") == 0) { - size_t files_count = 0, files_size = 0; + size_t files_count = 0, files_size = 0, len; alpm_file_t *files = NULL; - while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line)) { + while(fgets(line, sizeof(line), fp) && + (len = _alpm_strip_newline(line))) { if(files_count >= files_size) { size_t old_size = files_size; if(files_size == 0) { @@ -659,8 +658,14 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) memset(files + old_size, 0, sizeof(alpm_file_t) * (files_size - old_size)); } - STRDUP(files[files_count].name, line, goto error); - /* TODO: lstat file, get mode/size */ + /* since we know the length of the file string already, + * we can do malloc + memcpy rather than strdup */ + files[files_count].name = malloc(len + 1); + if(files[files_count].name == NULL) { + ALLOC_FAIL(len); + goto error; + } + memcpy(files[files_count].name, line, len + 1); files_count++; } /* attempt to hand back any memory we don't need */ @@ -794,11 +799,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..c602996d 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -18,11 +18,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #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 +38,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 +53,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 +102,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 +121,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 @@ -152,18 +171,21 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t * size_t len = _alpm_strip_newline(buf.line); linenum++; - if(len == 0 || buf.line[0] == '#') { + key = buf.line; + if(len == 0 || key[0] == '#') { continue; } - ptr = buf.line; - key = strsep(&ptr, "="); - if(key == NULL || ptr == NULL) { - _alpm_log(handle, ALPM_LOG_DEBUG, "%s: syntax error in description file line %d\n", - newpkg->name ? newpkg->name : "error", linenum); + /* line is always in this format: "key = value" + * we can be sure the " = " exists, so look for that */ + ptr = memchr(key, ' ', len); + if(!ptr || ptr - key + 2 > len || memcmp(ptr, " = ", 3) != 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "%s: syntax error in description file line %d\n", + newpkg->name ? newpkg->name : "error", linenum); } else { - key = _alpm_strtrim(key); - while(*ptr == ' ') ptr++; - ptr = _alpm_strtrim(ptr); + /* NULL the end of the key portion, move ptr to start of value */ + *ptr = '\0'; + ptr += 3; if(strcmp(key, "pkgname") == 0) { STRDUP(newpkg->name, ptr, return -1); newpkg->name_hash = _alpm_hash_sdbm(newpkg->name); @@ -355,7 +377,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 +389,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 +487,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 +516,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..abc4a997 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -18,10 +18,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> +#include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <unistd.h> /* libarchive */ @@ -212,6 +212,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 +235,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 +413,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 +425,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 +461,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..b5c55dc7 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -22,8 +22,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -318,12 +316,16 @@ const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist, const char *name) { size_t i; - const alpm_file_t *file = filelist->files; - for(i = 0; i < filelist->count; i++) { + const alpm_file_t *file; + + if(!filelist) { + return NULL; + } + + for(file = filelist->files, i = 0; i < filelist->count; file++, i++) { if(strcmp(file->name, name) == 0) { return file; } - file++; } return NULL; } @@ -383,11 +385,14 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, alpm_list_t *i, *conflicts = NULL; size_t numtargs = alpm_list_count(upgrade); size_t current; + size_t rootlen; if(!upgrade) { return NULL; } + rootlen = strlen(handle->root); + /* TODO this whole function needs a huge change, which hopefully will * be possible with real transactions. Right now we only do half as much * here as we do when we actually extract files in add.c with our 12 @@ -461,8 +466,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, int resolved_conflict = 0; struct stat lsbuf; char path[PATH_MAX]; + size_t pathlen; - snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); + pathlen = snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); /* stat the file - if it exists, do some checks */ if(_alpm_lstat(path, &lsbuf) != 0) { @@ -486,10 +492,10 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, /* if we made it to here, we want all subsequent path comparisons to * not include the trailing slash. This allows things like file -> * directory replacements. */ - path[strlen(path) - 1] = '\0'; + path[pathlen - 1] = '\0'; } - relative_path = path + strlen(handle->root); + relative_path = path + rootlen; /* Check remove list (will we remove the conflicting local file?) */ for(k = remove; k && !resolved_conflict; k = k->next) { @@ -542,9 +548,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, * components can be safely checked as all directories are "unowned". */ if(!resolved_conflict && dbpkg && !S_ISLNK(lsbuf.st_mode)) { char *rpath = calloc(PATH_MAX, sizeof(char)); - const char *relative_rpath; if(realpath(path, rpath)) { - relative_rpath = rpath + strlen(handle->root); + const char *relative_rpath = rpath + rootlen; if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) { _alpm_log(handle, ALPM_LOG_DEBUG, "package contained the resolved realpath\n"); diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 7708d18f..3e534358 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -22,8 +22,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <stdlib.h> #include <string.h> 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/delta.c b/lib/libalpm/delta.c index 6315a851..1272558e 100644 --- a/lib/libalpm/delta.c +++ b/lib/libalpm/delta.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> #include <stdint.h> /* intmax_t */ @@ -282,14 +280,17 @@ alpm_list_t SYMEXPORT *alpm_pkg_unused_deltas(alpm_pkg_t *pkg) alpm_delta_t *_alpm_delta_parse(char *line) { alpm_delta_t *delta; - char *tmp = line, *tmp2; + char *tmp; + const int num_matches = 6; + size_t len; regex_t reg; + regmatch_t pmatch[num_matches]; regcomp(®, - "^[^[:space:]]* [[:xdigit:]]{32} [[:digit:]]*" - " [^[:space:]]* [^[:space:]]*$", - REG_EXTENDED | REG_NOSUB | REG_NEWLINE); - if(regexec(®, line, 0, 0, 0) != 0) { + "^([^[:space:]]*) ([[:xdigit:]]{32}) ([[:digit:]]*)" + " ([^[:space:]]*) ([^[:space:]]*)$", + REG_EXTENDED | REG_NEWLINE); + if(regexec(®, line, num_matches, pmatch, 0) != 0) { /* delta line is invalid, return NULL */ regfree(®); return NULL; @@ -298,28 +299,22 @@ alpm_delta_t *_alpm_delta_parse(char *line) CALLOC(delta, 1, sizeof(alpm_delta_t), return NULL); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - STRDUP(delta->delta, tmp2, return NULL); + /* start at index 1 -- match 0 is the entire match */ + len = pmatch[1].rm_eo - pmatch[1].rm_so; + STRNDUP(tmp, &line[pmatch[1].rm_so], len, return NULL); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - STRDUP(delta->delta_md5, tmp2, return NULL); + len = pmatch[2].rm_eo - pmatch[2].rm_so; + STRNDUP(delta->delta_md5, &line[pmatch[2].rm_so], len, return NULL); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - delta->delta_size = _alpm_strtoofft(tmp2); + len = pmatch[3].rm_eo - pmatch[3].rm_so; + STRNDUP(tmp, &line[pmatch[3].rm_so], len, return NULL); + delta->delta_size = _alpm_strtoofft(tmp); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - STRDUP(delta->from, tmp2, return NULL); + len = pmatch[4].rm_eo - pmatch[4].rm_so; + STRNDUP(delta->from, &line[pmatch[4].rm_so], len, return NULL); - tmp2 = tmp; - STRDUP(delta->to, tmp2, return NULL); + len = pmatch[5].rm_eo - pmatch[5].rm_so; + STRNDUP(delta->to, &line[pmatch[5].rm_so], len, return NULL); return delta; } diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h index 05df4207..42353f5f 100644 --- a/lib/libalpm/delta.h +++ b/lib/libalpm/delta.h @@ -20,8 +20,6 @@ #ifndef _ALPM_DELTA_H #define _ALPM_DELTA_H -#include "config.h" /* ensure off_t is correct length */ - #include <sys/types.h> /* off_t */ #include "alpm.h" diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 89f6d691..9d7e5470 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -20,8 +20,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -395,7 +393,7 @@ int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep) /* any version will satisfy the requirement */ satisfy = (provision->name_hash == dep->name_hash && strcmp(provision->name, dep->name) == 0); - } else if (provision->mod == ALPM_DEP_MOD_EQ) { + } else if(provision->mod == ALPM_DEP_MOD_EQ) { /* provision specifies a version, so try it out */ satisfy = (provision->name_hash == dep->name_hash && strcmp(provision->name, dep->name) == 0 diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index fe2036d5..274aa676 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> #if defined(HAVE_MNTENT_H) #include <mntent.h> @@ -55,6 +53,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 +241,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 +375,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..a3980d65 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <errno.h> @@ -306,9 +304,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..528a3dcf 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #ifdef HAVE_LIBCURL #include <curl/curl.h> #endif @@ -29,12 +27,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/graph.c b/lib/libalpm/graph.c index 3a7f24b8..d080e05b 100644 --- a/lib/libalpm/graph.c +++ b/lib/libalpm/graph.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include "graph.h" #include "util.h" #include "log.h" diff --git a/lib/libalpm/graph.h b/lib/libalpm/graph.h index d4d134b5..2910b7d6 100644 --- a/lib/libalpm/graph.h +++ b/lib/libalpm/graph.h @@ -19,8 +19,6 @@ #ifndef _ALPM_GRAPH_H #define _ALPM_GRAPH_H -#include "config.h" /* ensure off_t is correct length */ - #include <sys/types.h> /* off_t */ #include "alpm_list.h" diff --git a/lib/libalpm/group.c b/lib/libalpm/group.c index 47458df2..8b407b26 100644 --- a/lib/libalpm/group.c +++ b/lib/libalpm/group.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 7402be50..6518b7d5 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -20,8 +20,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> #include <stdlib.h> #include <string.h> @@ -339,7 +337,7 @@ static char *canonicalize_path(const char *path) { return new_path; } -enum _alpm_errno_t _alpm_set_directory_option(const char *value, +alpm_errno_t _alpm_set_directory_option(const char *value, char **storage, int must_exist) { struct stat st; diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 8477dcae..1f147d6e 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -86,14 +86,14 @@ struct __alpm_handle_t { alpm_list_t *ignoregroup; /* List of groups to ignore */ /* options */ - int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ char *arch; /* Architecture of packages we should allow */ + int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ int usedelta; /* Download deltas if possible */ int checkspace; /* Check disk space before installing */ alpm_siglevel_t siglevel; /* Default signature verification level */ /* error code */ - enum _alpm_errno_t pm_errno; + alpm_errno_t pm_errno; }; alpm_handle_t *_alpm_handle_new(void); @@ -102,7 +102,7 @@ void _alpm_handle_free(alpm_handle_t *handle); int _alpm_handle_lock(alpm_handle_t *handle); int _alpm_handle_unlock(alpm_handle_t *handle); -enum _alpm_errno_t _alpm_set_directory_option(const char *value, +alpm_errno_t _alpm_set_directory_option(const char *value, char **storage, int must_exist); #endif /* _ALPM_HANDLE_H */ diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c index 692ff79c..14b454e6 100644 --- a/lib/libalpm/log.c +++ b/lib/libalpm/log.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <stdarg.h> #include <errno.h> diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index a5ff238f..68fec16a 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> #include <sys/types.h> @@ -87,12 +85,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 +198,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 +459,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 +516,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 +541,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 +561,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 +585,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 +596,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 +692,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..172d2f36 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -24,10 +24,7 @@ #ifndef _ALPM_PACKAGE_H #define _ALPM_PACKAGE_H -#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 +41,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 +86,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..b43d1a62 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -22,8 +22,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <errno.h> #include <string.h> @@ -216,7 +214,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 +237,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 +249,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 +273,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 +288,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 +312,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); @@ -350,38 +354,15 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, return 0; } -int _alpm_remove_single_package(alpm_handle_t *handle, +static int remove_package_files(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, size_t targ_count, size_t pkg_count) { alpm_list_t *skip_remove; - size_t filenum = 0, position = 0; - const char *pkgname = oldpkg->name; - const char *pkgver = oldpkg->version; alpm_filelist_t *filelist; - size_t i; - - if(newpkg) { - _alpm_log(handle, ALPM_LOG_DEBUG, "removing old package first (%s-%s)\n", - pkgname, pkgver); - } else { - EVENT(handle, ALPM_EVENT_REMOVE_START, oldpkg, NULL); - _alpm_log(handle, ALPM_LOG_DEBUG, "removing package %s-%s\n", - pkgname, pkgver); - - /* run the pre-remove scriptlet if it exists */ - if(alpm_pkg_has_scriptlet(oldpkg) && - !(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { - char *scriptlet = _alpm_local_db_pkgpath(handle->db_local, - oldpkg, "install"); - _alpm_runscriptlet(handle, scriptlet, "pre_remove", pkgver, NULL, 0); - free(scriptlet); - } - } - - if(handle->trans->flags & ALPM_TRANS_FLAG_DBONLY) { - goto db; - } + size_t i, filenum = 0, position = 0; + int err = 0; + int nosave = handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE; if(newpkg) { alpm_filelist_t *newfiles; @@ -412,32 +393,33 @@ int _alpm_remove_single_package(alpm_handle_t *handle, alpm_file_t *file = filelist->files + i; if(!can_remove_file(handle, file, skip_remove)) { _alpm_log(handle, ALPM_LOG_DEBUG, - "not removing package '%s', can't remove all files\n", pkgname); + "not removing package '%s', can't remove all files\n", + oldpkg->name); + FREELIST(skip_remove); RET_ERR(handle, ALPM_ERR_PKG_CANT_REMOVE, -1); } filenum++; } - _alpm_log(handle, ALPM_LOG_DEBUG, "removing %ld files\n", (unsigned long)filenum); + _alpm_log(handle, ALPM_LOG_DEBUG, "removing %zd files\n", filenum); if(!newpkg) { /* init progress bar, but only on true remove transactions */ - PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, pkgname, 0, + PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 0, pkg_count, targ_count); } /* iterate through the list backwards, unlinking files */ for(i = filelist->count; i > 0; i--) { alpm_file_t *file = filelist->files + i - 1; - int percent; - /* TODO: check return code and handle accordingly */ - unlink_file(handle, oldpkg, file, skip_remove, - handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE); + if(unlink_file(handle, oldpkg, newpkg, file, skip_remove, nosave) < 0) { + err++; + } if(!newpkg) { /* update progress bar after each file */ - percent = (position * 100) / filenum; - PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, pkgname, + int percent = (position * 100) / filenum; + PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, percent, pkg_count, targ_count); } position++; @@ -446,20 +428,56 @@ int _alpm_remove_single_package(alpm_handle_t *handle, if(!newpkg) { /* set progress to 100% after we finish unlinking files */ - PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, pkgname, 100, + PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 100, pkg_count, targ_count); + } + + return err; +} - /* run the post-remove script if it exists */ +int _alpm_remove_single_package(alpm_handle_t *handle, + alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, + size_t targ_count, size_t pkg_count) +{ + const char *pkgname = oldpkg->name; + const char *pkgver = oldpkg->version; + + if(newpkg) { + _alpm_log(handle, ALPM_LOG_DEBUG, "removing old package first (%s-%s)\n", + pkgname, pkgver); + } else { + EVENT(handle, ALPM_EVENT_REMOVE_START, oldpkg, NULL); + _alpm_log(handle, ALPM_LOG_DEBUG, "removing package %s-%s\n", + pkgname, pkgver); + + /* run the pre-remove scriptlet if it exists */ if(alpm_pkg_has_scriptlet(oldpkg) && !(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { char *scriptlet = _alpm_local_db_pkgpath(handle->db_local, oldpkg, "install"); - _alpm_runscriptlet(handle, scriptlet, "post_remove", pkgver, NULL, 0); + _alpm_runscriptlet(handle, scriptlet, "pre_remove", pkgver, NULL, 0); free(scriptlet); } } -db: + if(!(handle->trans->flags & ALPM_TRANS_FLAG_DBONLY)) { + /* TODO check returned errors if any */ + remove_package_files(handle, oldpkg, newpkg, targ_count, pkg_count); + } + + /* run the post-remove script if it exists */ + if(!newpkg && alpm_pkg_has_scriptlet(oldpkg) && + !(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { + char *scriptlet = _alpm_local_db_pkgpath(handle->db_local, + oldpkg, "install"); + _alpm_runscriptlet(handle, scriptlet, "post_remove", pkgver, NULL, 0); + free(scriptlet); + } + + if(!newpkg) { + EVENT(handle, ALPM_EVENT_REMOVE_DONE, oldpkg, NULL); + } + /* remove the package from the database */ _alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n"); _alpm_log(handle, ALPM_LOG_DEBUG, "removing database entry '%s'\n", pkgname); @@ -473,11 +491,6 @@ db: pkgname); } - if(!newpkg) { - /* TODO: awesome! we're passing invalid pointers. */ - EVENT(handle, ALPM_EVENT_REMOVE_DONE, oldpkg, NULL); - } - return 0; } diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 92f34b56..fbb6b134 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -270,6 +268,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..49a3f42d 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <sys/types.h> /* off_t */ #include <stdlib.h> #include <stdio.h> @@ -423,7 +421,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 +693,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 +755,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 +801,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 +905,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 +972,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; @@ -1117,7 +1158,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) trans->state = STATE_COMMITING; /* fileconflict check */ - if(!(trans->flags & ALPM_TRANS_FLAG_FORCE)) { + if(!(trans->flags & (ALPM_TRANS_FLAG_FORCE|ALPM_TRANS_FLAG_DBONLY))) { EVENT(handle, ALPM_EVENT_FILECONFLICTS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "looking for file conflicts\n"); @@ -1137,7 +1178,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) } /* check available disk space */ - if(handle->checkspace) { + if(handle->checkspace && !(trans->flags & ALPM_TRANS_FLAG_DBONLY)) { EVENT(handle, ALPM_EVENT_DISKSPACE_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space\n"); diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index cb97a4aa..5ceaaa70 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index ad15d937..fc0e0564 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -22,24 +22,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#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 +55,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 +94,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,92 +134,61 @@ 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); - return ret; -} - -/* Trim whitespace and newlines from a string -*/ -char *_alpm_strtrim(char *str) -{ - char *pch = str; - - if(*str == '\0') { - /* string is empty, so we're done. */ - return str; + if(in >= 0) { + CLOSE(in); } - - while(isspace((unsigned char)*pch)) { - pch++; - } - if(pch != str) { - size_t len = strlen(pch); - if(len) { - memmove(str, pch, len + 1); - } else { - *str = '\0'; - } - } - - /* check if there wasn't anything but whitespace in the string. */ - if(*str == '\0') { - return str; + if(out >= 0) { + CLOSE(out); } - - pch = (str + (strlen(str) - 1)); - while(isspace((unsigned char)*pch)) { - pch--; - } - *++pch = '\0'; - - return str; + return ret; } -/** - * 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 +209,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 +287,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 +326,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 +342,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 +352,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 +379,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 +438,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 +479,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 +517,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 +543,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 +564,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 +582,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 +591,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 +636,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 +664,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 +779,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 +847,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,24 +858,45 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) } } + CLOSE(fd); + free(buf); + + if(n < 0) { + return 2; + } + if(is224) { SHA224_Final(output, &ctx); } else { SHA256_Final(output, &ctx); } + return 0; +} +#endif - memset(&ctx, 0, sizeof(SHA256_CTX)); - free(buf); +/** Create a string representing bytes in hexadecimal. + * @param bytes the bytes to represent in hexadecimal + * @param size number of bytes to consider + * @return a NULL terminated string with the hexadecimal representation of + * bytes or NULL on error. This string must be freed. + */ +static char *hex_representation(unsigned char *bytes, size_t size) +{ + static const char *hex_digits = "0123456789abcdef"; + char *str; + size_t i; - if(ferror(f) != 0) { - fclose(f); - return 2; + MALLOC(str, 2 * size + 1, return NULL); + + for (i = 0; i < size; i++) { + str[2 * i] = hex_digits[bytes[i] >> 4]; + str[2 * i + 1] = hex_digits[bytes[i] & 0x0f]; } - fclose(f); - return 0; + str[2 * size] = '\0'; + + return str; } -#endif /** Get the md5 sum of file. * @param filename name of the file @@ -829,28 +906,15 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) char SYMEXPORT *alpm_compute_md5sum(const char *filename) { unsigned char output[16]; - char *md5sum; - int ret, i; ASSERT(filename != NULL, return NULL); - /* allocate 32 chars plus 1 for null */ - CALLOC(md5sum, 33, sizeof(char), return NULL); /* defined above for OpenSSL, otherwise defined in md5.h */ - ret = md5_file(filename, output); - - if(ret > 0) { - free(md5sum); + if(md5_file(filename, output) > 0) { return NULL; } - /* 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]); - } - - return md5sum; + return hex_representation(output, 16); } /** Get the sha256 sum of file. @@ -861,30 +925,24 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename) char SYMEXPORT *alpm_compute_sha256sum(const char *filename) { unsigned char output[32]; - char *sha256sum; - int ret, i; ASSERT(filename != NULL, return NULL); - /* allocate 64 chars plus 1 for null */ - CALLOC(sha256sum, 65, sizeof(char), return NULL); /* defined above for OpenSSL, otherwise defined in sha2.h */ - ret = sha2_file(filename, output, 0); - - if(ret > 0) { - free(sha256sum); + if(sha2_file(filename, output, 0) > 0) { return NULL; } - /* 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]); - } - - return sha256sum; + return hex_representation(output, 32); } +/** 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 +970,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 +997,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 +1020,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 +1040,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 +1052,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 +1071,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 +1131,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 +1151,11 @@ unsigned long _alpm_hash_sdbm(const char *str) return hash; } +/** Convert a string to a file offset. + * This parses bare positive integers only. + * @param line string to convert + * @return off_t on success, -1 on error + */ off_t _alpm_strtoofft(const char *line) { char *end; @@ -1089,13 +1167,13 @@ off_t _alpm_strtoofft(const char *line) return (off_t)-1; } result = strtoull(line, &end, 10); - if (result == 0 && end == line) { + if(result == 0 && end == line) { /* line was not a number */ return (off_t)-1; - } else if (result == ULLONG_MAX && errno == ERANGE) { + } else if(result == ULLONG_MAX && errno == ERANGE) { /* line does not fit in unsigned long long */ return (off_t)-1; - } else if (*end) { + } else if(*end) { /* line began with a number but has junk left over at the end */ return (off_t)-1; } @@ -1103,8 +1181,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 +1198,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,13 +1227,12 @@ time_t _alpm_parsedate(const char *line) * @param amode access mode as described in access() * @return int value returned by access() */ - int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int amode) { size_t len = 0; int ret = 0; - if (dir) { + if(dir) { char *check_path; len = strlen(dir) + strlen(file) + 1; @@ -1148,19 +1247,19 @@ int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int a } if(ret != 0) { - if (amode & R_OK) { + if(amode & R_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not readable: %s\n", dir, file, strerror(errno)); } - if (amode & W_OK) { + if(amode & W_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not writable: %s\n", dir, file, strerror(errno)); } - if (amode & X_OK) { + if(amode & X_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not executable: %s\n", dir, file, strerror(errno)); } - if (amode == F_OK) { + if(amode == F_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" does not exist: %s\n", dir, file, strerror(errno)); } @@ -1168,8 +1267,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 +1293,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..6d5c0c35 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -24,8 +24,6 @@ #ifndef _ALPM_UTIL_H #define _ALPM_UTIL_H -#include "config.h" - #include "alpm_list.h" #include "alpm.h" #include "package.h" /* alpm_pkg_t */ @@ -35,11 +33,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 +51,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 +82,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(). */ @@ -106,8 +113,10 @@ enum _alpm_csum { int _alpm_makepath(const char *path); int _alpm_makepath_mode(const char *path, mode_t mode); int _alpm_copyfile(const char *src, const char *dest); -char *_alpm_strtrim(char *str); 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 +124,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 +136,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 *); diff --git a/lib/libalpm/version.c b/lib/libalpm/version.c index 6b65a413..a88b8180 100644 --- a/lib/libalpm/version.c +++ b/lib/libalpm/version.c @@ -15,8 +15,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <string.h> #include <ctype.h> |