diff options
Diffstat (limited to 'lib/libalpm')
-rw-r--r-- | lib/libalpm/add.c | 98 | ||||
-rw-r--r-- | lib/libalpm/alpm.h | 16 | ||||
-rw-r--r-- | lib/libalpm/alpm_list.c | 13 | ||||
-rw-r--r-- | lib/libalpm/alpm_list.h | 1 | ||||
-rw-r--r-- | lib/libalpm/base64.c | 2 | ||||
-rw-r--r-- | lib/libalpm/base64.h | 2 | ||||
-rw-r--r-- | lib/libalpm/be_local.c | 9 | ||||
-rw-r--r-- | lib/libalpm/be_package.c | 50 | ||||
-rw-r--r-- | lib/libalpm/be_sync.c | 54 | ||||
-rw-r--r-- | lib/libalpm/conflict.c | 10 | ||||
-rw-r--r-- | lib/libalpm/db.h | 2 | ||||
-rw-r--r-- | lib/libalpm/diskspace.c | 102 | ||||
-rw-r--r-- | lib/libalpm/diskspace.h | 2 | ||||
-rw-r--r-- | lib/libalpm/dload.c | 4 | ||||
-rw-r--r-- | lib/libalpm/dload.h | 3 | ||||
-rw-r--r-- | lib/libalpm/package.c | 10 | ||||
-rw-r--r-- | lib/libalpm/package.h | 9 | ||||
-rw-r--r-- | lib/libalpm/remove.c | 16 | ||||
-rw-r--r-- | lib/libalpm/sync.c | 193 | ||||
-rw-r--r-- | lib/libalpm/util.c | 252 | ||||
-rw-r--r-- | lib/libalpm/util.h | 19 |
21 files changed, 511 insertions, 356 deletions
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 6c2f0cb6..d66ab934 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -22,7 +22,6 @@ #include <stdlib.h> #include <errno.h> -#include <time.h> #include <string.h> #include <limits.h> #include <fcntl.h> @@ -132,6 +131,18 @@ static int perform_extraction(alpm_handle_t *handle, struct archive *archive, return 0; } +static int try_rename(alpm_handle_t *handle, const char *src, const char *dest) +{ + if(rename(src, dest)) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), + src, dest, strerror(errno)); + alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", + src, dest, strerror(errno)); + return 1; + } + return 0; +} + static int extract_single_file(alpm_handle_t *handle, struct archive *archive, struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg) { @@ -146,8 +157,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, entryname = archive_entry_pathname(entry); entrymode = archive_entry_mode(entry); - memset(filename, 0, PATH_MAX); /* just to be sure */ - if(strcmp(entryname, ".INSTALL") == 0) { /* the install script goes inside the db */ snprintf(filename, PATH_MAX, "%s%s-%s/install", @@ -282,17 +291,18 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); if(needbackup) { - char checkfile[PATH_MAX]; + char *checkfile; char *hash_local = NULL, *hash_pkg = NULL; - int ret; + size_t len; - snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); + len = strlen(filename) + 10; + MALLOC(checkfile, len, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(checkfile, len, "%s.paccheck", filename); - ret = perform_extraction(handle, archive, entry, checkfile, entryname_orig); - if(ret == 1) { - /* error */ - FREE(entryname_orig); - return 1; + if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) { + errors++; + goto needbackup_cleanup; } hash_local = alpm_compute_md5sum(filename); @@ -320,29 +330,26 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) { /* looks like we have a local file that has a different hash as the * file in the package, move it to a .pacorig */ - char newpath[PATH_MAX]; - snprintf(newpath, PATH_MAX, "%s.pacorig", filename); + char *newpath; + size_t newlen = strlen(filename) + 9; + MALLOC(newpath, newlen, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(newpath, newlen, "%s.pacorig", filename); /* move the existing file to the "pacorig" */ - if(rename(filename, newpath)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - filename, newpath, strerror(errno)); - alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", - filename, newpath, strerror(errno)); + if(try_rename(handle, filename, newpath)) { + errors++; errors++; } else { /* rename the file we extracted to the real name */ - if(rename(checkfile, filename)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - checkfile, filename, strerror(errno)); - alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", - checkfile, filename, strerror(errno)); + if(try_rename(handle, checkfile, filename)) { errors++; } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); alpm_logaction(handle, "warning: %s saved as %s\n", filename, newpath); } } + free(newpath); } else { /* local file is identical to pkg one, so just remove pkg one */ unlink(checkfile); @@ -356,11 +363,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", entryname_orig); - if(rename(checkfile, filename)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - checkfile, filename, strerror(errno)); - alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", - checkfile, filename, strerror(errno)); + if(try_rename(handle, checkfile, filename)) { errors++; } } else { @@ -382,29 +385,30 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); unlink(checkfile); } else { - char newpath[PATH_MAX]; + char *newpath; + size_t newlen = strlen(filename) + 8; _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" " new one with .pacnew ending\n"); - snprintf(newpath, PATH_MAX, "%s.pacnew", filename); - if(rename(checkfile, newpath)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not install %s as %s (%s)\n"), - filename, newpath, strerror(errno)); - alpm_logaction(handle, "error: could not install %s as %s (%s)\n", - filename, newpath, strerror(errno)); + MALLOC(newpath, newlen, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(newpath, newlen, "%s.pacnew", filename); + if(try_rename(handle, checkfile, newpath)) { + errors++; } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), filename, newpath); alpm_logaction(handle, "warning: %s installed as %s\n", filename, newpath); } + free(newpath); } } - FREE(hash_local); - FREE(hash_pkg); +needbackup_cleanup: + free(checkfile); + free(hash_local); + free(hash_pkg); } else { - int ret; - /* we didn't need a backup */ if(notouch) { /* change the path to a .pacnew extension */ @@ -423,11 +427,11 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, unlink(filename); } - ret = perform_extraction(handle, archive, entry, filename, entryname_orig); - if(ret == 1) { + if(perform_extraction(handle, archive, entry, filename, entryname_orig)) { /* error */ - FREE(entryname_orig); - return 1; + free(entryname_orig); + errors++; + return errors; } /* calculate an hash if this is in newpkg's backup */ @@ -444,7 +448,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, backup->hash = newhash; } } - FREE(entryname_orig); + free(entryname_orig); return errors; } @@ -543,9 +547,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, } /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -602,7 +604,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } if(errors) { diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index a93d4e3e..9fda9406 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -27,9 +27,9 @@ extern "C" { #endif -#include <sys/types.h> /* for off_t */ -#include <time.h> /* for time_t */ -#include <stdarg.h> /* for va_list */ +#include <inttypes.h> /* int64_t */ +#include <sys/types.h> /* off_t */ +#include <stdarg.h> /* va_list */ #include <alpm_list.h> @@ -44,6 +44,8 @@ extern "C" { * @{ */ +typedef int64_t alpm_time_t; + /* * Enumerations * These ones are used in multiple contexts, so are forward-declared. @@ -222,8 +224,8 @@ typedef struct _alpm_pgpkey_t { char *uid; char *name; char *email; - time_t created; - time_t expires; + alpm_time_t created; + alpm_time_t expires; } alpm_pgpkey_t; /** Signature result. Contains the key, status, and validity of a given @@ -754,13 +756,13 @@ const char *alpm_pkg_get_url(alpm_pkg_t *pkg); * @param pkg a pointer to package * @return the timestamp of the build time */ -time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg); +alpm_time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg); /** Returns the install timestamp of the package. * @param pkg a pointer to package * @return the timestamp of the install time */ -time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg); +alpm_time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg); /** Returns the packager's name. * @param pkg a pointer to package diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index 15286aa1..cad6d096 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -576,19 +576,6 @@ alpm_list_t SYMEXPORT *alpm_list_last(const alpm_list_t *list) } } -/** - * @brief Get the data member of a list node. - * - * @param node the list node - * - * @return the contained data, or NULL if none - */ -void SYMEXPORT *alpm_list_getdata(const alpm_list_t *node) -{ - if(node == NULL) return NULL; - return node->data; -} - /* Misc */ /** diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index cd7b0291..9f69e2c2 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -71,7 +71,6 @@ alpm_list_t *alpm_list_nth(const alpm_list_t *list, size_t n); alpm_list_t *alpm_list_next(const alpm_list_t *list); alpm_list_t *alpm_list_previous(const alpm_list_t *list); alpm_list_t *alpm_list_last(const alpm_list_t *list); -void *alpm_list_getdata(const alpm_list_t *entry); /* misc */ size_t alpm_list_count(const alpm_list_t *list); diff --git a/lib/libalpm/base64.c b/lib/libalpm/base64.c index 5c9fa814..0d29f656 100644 --- a/lib/libalpm/base64.c +++ b/lib/libalpm/base64.c @@ -62,6 +62,7 @@ static const unsigned char base64_dec_map[128] = 49, 50, 51, 127, 127, 127, 127, 127 }; +#if 0 /* * Encode a buffer into base64 format */ @@ -124,6 +125,7 @@ int base64_encode( unsigned char *dst, size_t *dlen, return( 0 ); } +#endif /* * Decode a base64-formatted buffer diff --git a/lib/libalpm/base64.h b/lib/libalpm/base64.h index 406aefa1..df684ab7 100644 --- a/lib/libalpm/base64.h +++ b/lib/libalpm/base64.h @@ -30,6 +30,7 @@ #define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x0010 /**< Output buffer too small. */ #define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x0012 /**< Invalid character in input. */ +#if 0 /** * \brief Encode a buffer into base64 format * @@ -47,6 +48,7 @@ */ int base64_encode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ); +#endif /** * \brief Decode a base64-formatted buffer diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 56cf38bb..21d27481 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -28,7 +28,6 @@ #include <stdint.h> /* intmax_t */ #include <sys/stat.h> #include <dirent.h> -#include <time.h> #include <limits.h> /* PATH_MAX */ /* libalpm */ @@ -69,13 +68,13 @@ static const char *_cache_get_url(alpm_pkg_t *pkg) return pkg->url; } -static time_t _cache_get_builddate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_builddate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, 0); return pkg->builddate; } -static time_t _cache_get_installdate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_installdate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, 0); return pkg->installdate; @@ -794,11 +793,11 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq } if(info->builddate) { fprintf(fp, "%%BUILDDATE%%\n" - "%ld\n\n", info->builddate); + "%jd\n\n", (intmax_t)info->builddate); } if(info->installdate) { fprintf(fp, "%%INSTALLDATE%%\n" - "%ld\n\n", info->installdate); + "%jd\n\n", (intmax_t)info->installdate); } if(info->packager) { fprintf(fp, "%%PACKAGER%%\n" diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index 4d9d0e82..90a19722 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -23,6 +23,9 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> /* libarchive */ #include <archive.h> @@ -355,7 +358,7 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, int full) { - int ret, config = 0; + int ret, fd, config = 0; struct archive *archive; struct archive_entry *entry; alpm_pkg_t *newpkg = NULL; @@ -367,34 +370,41 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL); } - /* attempt to stat the package file, ensure it exists */ - if(stat(pkgfile, &st) == 0) { - newpkg = _alpm_pkg_new(); - if(newpkg == NULL) { - RET_ERR(handle, ALPM_ERR_MEMORY, NULL); - } - newpkg->filename = strdup(pkgfile); - newpkg->size = st.st_size; - } else { - /* couldn't stat the pkgfile, return an error */ - RET_ERR(handle, ALPM_ERR_PKG_NOT_FOUND, NULL); - } - /* try to create an archive object to read in the package */ if((archive = archive_read_new()) == NULL) { - alpm_pkg_free(newpkg); RET_ERR(handle, ALPM_ERR_LIBARCHIVE, NULL); } archive_read_support_compression_all(archive); archive_read_support_format_all(archive); - if(archive_read_open_filename(archive, pkgfile, + OPEN(fd, pkgfile, O_RDONLY); + if(fd < 0 || archive_read_open_fd(archive, fd, ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - alpm_pkg_free(newpkg); - RET_ERR(handle, ALPM_ERR_PKG_OPEN, NULL); + const char *err = fd < 0 ? strerror(errno) : archive_error_string(archive); + _alpm_log(handle, ALPM_LOG_ERROR, + _("could not open file %s: %s\n"), pkgfile, err); + if(fd < 0 && errno == ENOENT) { + handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND; + } else { + handle->pm_errno = ALPM_ERR_PKG_OPEN; + } + goto error; } + newpkg = _alpm_pkg_new(); + if(newpkg == NULL) { + handle->pm_errno = ALPM_ERR_MEMORY; + goto error; + } + if(fstat(fd, &st) != 0) { + handle->pm_errno = ALPM_ERR_PKG_OPEN; + goto error; + } + STRDUP(newpkg->filename, pkgfile, + handle->pm_errno = ALPM_ERR_MEMORY; goto error); + newpkg->size = st.st_size; + _alpm_log(handle, ALPM_LOG_DEBUG, "starting package load for %s\n", pkgfile); /* If full is false, only read through the archive until we find our needed @@ -476,6 +486,7 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, } archive_read_finish(archive); + CLOSE(fd); /* internal fields for package struct */ newpkg->origin = PKG_FROM_FILE; @@ -504,6 +515,9 @@ pkg_invalid: error: _alpm_pkg_free(newpkg); archive_read_finish(archive); + if(fd >= 0) { + CLOSE(fd); + } return NULL; } diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 3c990246..aa260020 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -21,7 +21,9 @@ #include "config.h" #include <errno.h> +#include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <unistd.h> /* libarchive */ @@ -212,6 +214,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* print server + filename into a buffer */ len = strlen(server) + strlen(db->treename) + 5; + /* TODO fix leak syncpath and umask unset */ MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload.fileurl, len, "%s/%s.db", server, db->treename); payload.handle = handle; @@ -234,6 +237,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* if we downloaded a DB, we want the .sig from the same server */ /* print server + filename into a buffer (leave space for .sig) */ len = strlen(server) + strlen(db->treename) + 9; + /* TODO fix leak syncpath and umask unset */ MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload.fileurl, len, "%s/%s.db.sig", server, db->treename); payload.handle = handle; @@ -411,7 +415,7 @@ static int sync_db_populate(alpm_db_t *db) { const char *dbpath; size_t est_count; - int count = 0; + int count = -1, fd; struct stat buf; struct archive *archive; struct archive_entry *entry; @@ -423,6 +427,11 @@ static int sync_db_populate(alpm_db_t *db) if(db->status & DB_STATUS_MISSING) { RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1); } + dbpath = _alpm_db_path(db); + if(!dbpath) { + /* pm_errno set in _alpm_db_path() */ + return -1; + } if((archive = archive_read_new()) == NULL) { RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1); @@ -431,30 +440,28 @@ static int sync_db_populate(alpm_db_t *db) archive_read_support_compression_all(archive); archive_read_support_format_all(archive); - dbpath = _alpm_db_path(db); - if(!dbpath) { - /* pm_errno set in _alpm_db_path() */ - return -1; - } - - _alpm_log(db->handle, ALPM_LOG_DEBUG, "opening database archive %s\n", dbpath); - - if(archive_read_open_filename(archive, dbpath, + _alpm_log(db->handle, ALPM_LOG_DEBUG, + "opening database archive %s\n", dbpath); + OPEN(fd, dbpath, O_RDONLY); + if(fd < 0 || archive_read_open_fd(archive, fd, ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath, - archive_error_string(archive)); - archive_read_finish(archive); - RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); + const char *err = fd < 0 ? strerror(errno) : archive_error_string(archive); + _alpm_log(db->handle, ALPM_LOG_ERROR, + _("could not open file %s: %s\n"), dbpath, err); + db->handle->pm_errno = ALPM_ERR_DB_OPEN; + goto cleanup; } - if(stat(dbpath, &buf) != 0) { - RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); + if(fstat(fd, &buf) != 0) { + db->handle->pm_errno = ALPM_ERR_DB_OPEN; + goto cleanup; } est_count = estimate_package_count(&buf, archive); /* initialize hash at 66% full */ db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2); if(db->pkgcache == NULL) { - RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); + db->handle->pm_errno = ALPM_ERR_MEMORY; + goto cleanup; } while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { @@ -473,14 +480,19 @@ static int sync_db_populate(alpm_db_t *db) } count = alpm_list_count(db->pkgcache->list); - if(count > 0) { - db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp); + db->pkgcache->list = alpm_list_msort(db->pkgcache->list, + (size_t)count, _alpm_pkg_cmp); } - archive_read_finish(archive); - _alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n", + _alpm_log(db->handle, ALPM_LOG_DEBUG, + "added %d packages to package cache for db '%s'\n", count, db->treename); +cleanup: + archive_read_finish(archive); + if(fd >= 0) { + CLOSE(fd); + } return count; } diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 32f6f303..486f4bf3 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -318,12 +318,16 @@ const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist, const char *name) { size_t i; - const alpm_file_t *file = filelist->files; - for(i = 0; i < filelist->count; i++) { + const alpm_file_t *file; + + if(!filelist) { + return NULL; + } + + for(file = filelist->files, i = 0; i < filelist->count; file++, i++) { if(strcmp(file->name, name) == 0) { return file; } - file++; } return NULL; } diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 224bfbeb..a1249d3e 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -22,8 +22,6 @@ #ifndef _ALPM_DB_H #define _ALPM_DB_H -#include <time.h> - /* libarchive */ #include <archive.h> #include <archive_entry.h> diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index fe2036d5..cfd6402c 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -55,6 +55,17 @@ static int mount_point_cmp(const void *p1, const void *p2) return -strcmp(mp1->mount_dir, mp2->mount_dir); } +static void mount_point_list_free(alpm_list_t *mount_points) +{ + alpm_list_t *i; + + for(i = mount_points; i; i = i->next) { + alpm_mountpoint_t *data = i->data; + FREE(data->mount_dir); + } + FREELIST(mount_points); +} + static alpm_list_t *mount_point_list(alpm_handle_t *handle) { alpm_list_t *mount_points = NULL, *ptr; @@ -232,6 +243,72 @@ static int calculate_installed_size(alpm_handle_t *handle, return 0; } +static int check_mountpoint(alpm_handle_t *handle, alpm_mountpoint_t *mp) +{ + /* cushion is roughly min(5% capacity, 20MiB) */ + fsblkcnt_t fivepc = (mp->fsp.f_blocks / 20) + 1; + fsblkcnt_t twentymb = (20 * 1024 * 1024 / mp->fsp.f_bsize) + 1; + fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb; + blkcnt_t needed = mp->max_blocks_needed + cushion; + + _alpm_log(handle, ALPM_LOG_DEBUG, + "partition %s, needed %jd, cushion %ju, free %ju\n", + mp->mount_dir, (intmax_t)mp->max_blocks_needed, + (uintmax_t)cushion, (uintmax_t)mp->fsp.f_bfree); + if(needed >= 0 && (fsblkcnt_t)needed > mp->fsp.f_bfree) { + _alpm_log(handle, ALPM_LOG_ERROR, + _("Partition %s too full: %jd blocks needed, %jd blocks free\n"), + mp->mount_dir, (intmax_t)needed, (uintmax_t)mp->fsp.f_bfree); + return 1; + } + return 0; +} + +int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir, + size_t num_files, off_t *file_sizes) +{ + alpm_list_t *mount_points; + alpm_mountpoint_t *cachedir_mp; + size_t j; + int error = 0; + + mount_points = mount_point_list(handle); + if(mount_points == NULL) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n")); + return -1; + } + + cachedir_mp = match_mount_point(mount_points, cachedir); + if(cachedir == NULL) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not determine cachedir mount point %s\n"), + cachedir); + error = 1; + goto finish; + } + + /* there's no need to check for a R/O mounted filesystem here, as + * _alpm_filecache_setup will never give us a non-writable directory */ + + /* round up the size of each file to the nearest block and accumulate */ + for(j = 0; j < num_files; j++) { + cachedir_mp->max_blocks_needed += (file_sizes[j] + cachedir_mp->fsp.f_bsize + 1) / + cachedir_mp->fsp.f_bsize; + } + + if(check_mountpoint(handle, cachedir_mp)) { + error = 1; + } + +finish: + mount_point_list_free(mount_points); + + if(error) { + RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); + } + + return 0; +} + int _alpm_check_diskspace(alpm_handle_t *handle) { alpm_list_t *mount_points, *i; @@ -300,32 +377,13 @@ int _alpm_check_diskspace(alpm_handle_t *handle) _alpm_log(handle, ALPM_LOG_ERROR, _("Partition %s is mounted read only\n"), data->mount_dir); error = 1; - } else if(data->used & USED_INSTALL) { - /* cushion is roughly min(5% capacity, 20MiB) */ - fsblkcnt_t fivepc = (data->fsp.f_blocks / 20) + 1; - fsblkcnt_t twentymb = (20 * 1024 * 1024 / data->fsp.f_bsize) + 1; - fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb; - blkcnt_t needed = data->max_blocks_needed + cushion; - - _alpm_log(handle, ALPM_LOG_DEBUG, - "partition %s, needed %jd, cushion %ju, free %ju\n", - data->mount_dir, (intmax_t)data->max_blocks_needed, - (uintmax_t)cushion, (uintmax_t)data->fsp.f_bfree); - if(needed >= 0 && (fsblkcnt_t)needed > data->fsp.f_bfree) { - _alpm_log(handle, ALPM_LOG_ERROR, - _("Partition %s too full: %jd blocks needed, %jd blocks free\n"), - data->mount_dir, (intmax_t)needed, (uintmax_t)data->fsp.f_bfree); - error = 1; - } + } else if(data->used & USED_INSTALL && check_mountpoint(handle, data)) { + error = 1; } } finish: - for(i = mount_points; i; i = i->next) { - alpm_mountpoint_t *data = i->data; - FREE(data->mount_dir); - } - FREELIST(mount_points); + mount_point_list_free(mount_points); if(error) { RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); diff --git a/lib/libalpm/diskspace.h b/lib/libalpm/diskspace.h index 5944bb17..a613e232 100644 --- a/lib/libalpm/diskspace.h +++ b/lib/libalpm/diskspace.h @@ -50,6 +50,8 @@ typedef struct __alpm_mountpoint_t { } alpm_mountpoint_t; int _alpm_check_diskspace(alpm_handle_t *handle); +int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir, + size_t num_files, off_t *file_sizes); #endif /* _ALPM_DISKSPACE_H */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index efd469d5..76bb00f9 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -306,9 +306,7 @@ static FILE *create_tempfile(struct dload_payload *payload, const char *localpat fchmod(fd, ~(_getumask()) & 0666) || !(fp = fdopen(fd, payload->tempfile_openmode))) { unlink(randpath); - if(fd >= 0) { - close(fd); - } + CLOSE(fd); _alpm_log(payload->handle, ALPM_LOG_ERROR, _("failed to create temporary file for download\n")); return NULL; diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index f5f2cd9c..9ab90b42 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -23,8 +23,6 @@ #include "alpm_list.h" #include "alpm.h" -#include <time.h> - struct dload_payload { alpm_handle_t *handle; const char *tempfile_openmode; @@ -40,6 +38,7 @@ struct dload_payload { int allow_resume; int errors_ok; int unlink_on_fail; + alpm_list_t *servers; #ifdef HAVE_LIBCURL CURLcode curlerr; /* last error produced by curl */ #endif diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index a5ff238f..0b0bf6e4 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -87,12 +87,12 @@ int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg) * populated package structures. */ static const char *_pkg_get_desc(alpm_pkg_t *pkg) { return pkg->desc; } static const char *_pkg_get_url(alpm_pkg_t *pkg) { return pkg->url; } -static time_t _pkg_get_builddate(alpm_pkg_t *pkg) { return pkg->builddate; } -static time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; } +static alpm_time_t _pkg_get_builddate(alpm_pkg_t *pkg) { return pkg->builddate; } +static alpm_time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; } static const char *_pkg_get_packager(alpm_pkg_t *pkg) { return pkg->packager; } static const char *_pkg_get_arch(alpm_pkg_t *pkg) { return pkg->arch; } static off_t _pkg_get_isize(alpm_pkg_t *pkg) { return pkg->isize; } -static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg) { return pkg->reason; } +static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg) { return pkg->reason; } static int _pkg_has_scriptlet(alpm_pkg_t *pkg) { return pkg->scriptlet; } static alpm_list_t *_pkg_get_licenses(alpm_pkg_t *pkg) { return pkg->licenses; } @@ -200,14 +200,14 @@ const char SYMEXPORT *alpm_pkg_get_url(alpm_pkg_t *pkg) return pkg->ops->get_url(pkg); } -time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg) +alpm_time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return -1); pkg->handle->pm_errno = 0; return pkg->ops->get_builddate(pkg); } -time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg) +alpm_time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return -1); pkg->handle->pm_errno = 0; diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index eff7d898..82a83264 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -27,7 +27,6 @@ #include "config.h" /* ensure off_t is correct length */ #include <sys/types.h> /* off_t */ -#include <time.h> /* time_t */ #include "alpm.h" #include "backup.h" @@ -44,8 +43,8 @@ struct pkg_operations { const char *(*get_desc) (alpm_pkg_t *); const char *(*get_url) (alpm_pkg_t *); - time_t (*get_builddate) (alpm_pkg_t *); - time_t (*get_installdate) (alpm_pkg_t *); + alpm_time_t (*get_builddate) (alpm_pkg_t *); + alpm_time_t (*get_installdate) (alpm_pkg_t *); const char *(*get_packager) (alpm_pkg_t *); const char *(*get_arch) (alpm_pkg_t *); off_t (*get_isize) (alpm_pkg_t *); @@ -89,8 +88,8 @@ struct __alpm_pkg_t { char *base64_sig; char *arch; - time_t builddate; - time_t installdate; + alpm_time_t builddate; + alpm_time_t installdate; off_t size; off_t isize; diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 44f3ee93..cf137ae8 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -239,8 +239,9 @@ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file, /* Helper function for iterating through a package's file and deleting them * Used by _alpm_remove_commit. */ -static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, - const alpm_file_t *fileobj, alpm_list_t *skip_remove, int nosave) +static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, + alpm_pkg_t *newpkg, const alpm_file_t *fileobj, alpm_list_t *skip_remove, + int nosave) { struct stat buf; char file[PATH_MAX]; @@ -274,6 +275,10 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, } else if(files < 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (could not count files)\n", file); + } else if(newpkg && _alpm_filelist_contains(alpm_pkg_get_files(newpkg), + fileobj->name)) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "keeping directory %s (in new package)\n", file); } else { /* one last check- does any other package own this file? */ alpm_list_t *local, *local_pkgs; @@ -285,7 +290,8 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, /* we duplicated the package when we put it in the removal list, so we * so we can't use direct pointer comparison here. */ - if(_alpm_pkg_cmp(info, local_pkg) == 0) { + if(oldpkg->name_hash == local_pkg->name_hash + && strcmp(oldpkg->name, local_pkg->name) == 0) { continue; } filelist = alpm_pkg_get_files(local_pkg); @@ -308,7 +314,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, } } else { /* if the file needs backup and has been modified, back it up to .pacsave */ - alpm_backup_t *backup = _alpm_needbackup(fileobj->name, info); + alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg); if(backup) { if(nosave) { _alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); @@ -431,7 +437,7 @@ int _alpm_remove_single_package(alpm_handle_t *handle, alpm_file_t *file = filelist->files + i - 1; int percent; /* TODO: check return code and handle accordingly */ - unlink_file(handle, oldpkg, file, skip_remove, + unlink_file(handle, oldpkg, newpkg, file, skip_remove, handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE); if(!newpkg) { diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 54b9794a..52049a8c 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -686,11 +686,11 @@ static int apply_deltas(alpm_handle_t *handle) } else { /* len = cachedir len + from len + '/' + null */ len = strlen(cachedir) + strlen(d->from) + 2; - CALLOC(from, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); + MALLOC(from, len, RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(from, len, "%s/%s", cachedir, d->from); } len = strlen(cachedir) + strlen(d->to) + 2; - CALLOC(to, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); + MALLOC(to, len, RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(to, len, "%s/%s", cachedir, d->to); /* build the patch command */ @@ -794,11 +794,92 @@ static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas) return 0; } +static struct dload_payload *build_payload(alpm_handle_t *handle, + const char *filename, size_t size, alpm_list_t *servers) +{ + struct dload_payload *payload; + + CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + STRDUP(payload->remote_name, filename, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + payload->max_size = size; + payload->servers = servers; + return payload; +} + +static int find_dl_candidates(alpm_db_t *repo, alpm_list_t **files, alpm_list_t **deltas) +{ + alpm_list_t *i; + alpm_handle_t *handle = repo->handle; + + for(i = handle->trans->add; i; i = i->next) { + alpm_pkg_t *spkg = i->data; + + if(spkg->origin != PKG_FROM_FILE && repo == spkg->origin_data.db) { + alpm_list_t *delta_path = spkg->delta_path; + + if(!repo->servers) { + handle->pm_errno = ALPM_ERR_SERVER_NONE; + _alpm_log(handle, ALPM_LOG_ERROR, "%s: %s\n", + alpm_strerror(handle->pm_errno), repo->treename); + return 1; + } + + if(delta_path) { + /* using deltas */ + alpm_list_t *dlts; + for(dlts = delta_path; dlts; dlts = dlts->next) { + alpm_delta_t *delta = dlts->data; + if(delta->download_size != 0) { + struct dload_payload *payload = build_payload( + handle, delta->delta, delta->download_size, repo->servers); + ASSERT(payload, return -1); + *files = alpm_list_add(*files, payload); + } + /* keep a list of all the delta files for md5sums */ + *deltas = alpm_list_add(*deltas, delta); + } + + } else if(spkg->download_size != 0) { + struct dload_payload *payload; + ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); + payload = build_payload(handle, spkg->filename, spkg->size, repo->servers); + ASSERT(payload, return -1); + *files = alpm_list_add(*files, payload); + } + } + } + + return 0; +} + +static int download_single_file(alpm_handle_t *handle, struct dload_payload *payload, + const char *cachedir) +{ + const alpm_list_t *server; + + for(server = payload->servers; server; server = server->next) { + const char *server_url = server->data; + size_t len; + + /* print server + filename into a buffer */ + len = strlen(server_url) + strlen(payload->remote_name) + 2; + MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + snprintf(payload->fileurl, len, "%s/%s", server_url, payload->remote_name); + payload->handle = handle; + payload->allow_resume = 1; + + if(_alpm_download(payload, cachedir, NULL) != -1) { + return 0; + } + } + + return -1; +} + static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) { const char *cachedir; - alpm_list_t *i, *j; - alpm_list_t *files = NULL; + alpm_list_t *i, *files = NULL; int errors = 0; cachedir = _alpm_filecache_setup(handle); @@ -817,91 +898,53 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) handle->totaldlcb(total_size); } - /* group sync records by repository and download */ for(i = handle->dbs_sync; i; i = i->next) { - alpm_db_t *current = i->data; - - for(j = handle->trans->add; j; j = j->next) { - alpm_pkg_t *spkg = j->data; - - if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) { - alpm_list_t *delta_path = spkg->delta_path; - if(delta_path) { - /* using deltas */ - alpm_list_t *dlts; - for(dlts = delta_path; dlts; dlts = dlts->next) { - alpm_delta_t *delta = dlts->data; - if(delta->download_size != 0) { - struct dload_payload *dpayload; - - CALLOC(dpayload, 1, sizeof(*dpayload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - STRDUP(dpayload->remote_name, delta->delta, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - dpayload->max_size = delta->download_size; - - files = alpm_list_add(files, dpayload); - } - /* keep a list of all the delta files for md5sums */ - *deltas = alpm_list_add(*deltas, delta); - } + errors += find_dl_candidates(i->data, &files, deltas); + } - } else if(spkg->download_size != 0) { - struct dload_payload *payload; + if(files) { + /* check for necessary disk space for download */ + if(handle->checkspace) { + off_t *file_sizes; + size_t idx, num_files; + int ret; - ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); - CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - STRDUP(payload->remote_name, spkg->filename, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - payload->max_size = spkg->size; + _alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space for download\n"); - files = alpm_list_add(files, payload); - } + num_files = alpm_list_count(files); + CALLOC(file_sizes, num_files, sizeof(off_t), goto finish); + for(i = files, idx = 0; i; i = i->next, idx++) { + const struct dload_payload *payload = i->data; + file_sizes[idx] = payload->max_size; } - } - if(files) { - if(!current->servers) { - handle->pm_errno = ALPM_ERR_SERVER_NONE; - _alpm_log(handle, ALPM_LOG_ERROR, "%s: %s\n", - alpm_strerror(handle->pm_errno), current->treename); + ret = _alpm_check_downloadspace(handle, cachedir, num_files, file_sizes); + free(file_sizes); + + if(ret != 0) { errors++; - continue; + goto finish; } + } - EVENT(handle, ALPM_EVENT_RETRIEVE_START, current->treename, NULL); - for(j = files; j; j = j->next) { - struct dload_payload *payload = j->data; - alpm_list_t *server; - int ret = -1; - for(server = current->servers; server; server = server->next) { - const char *server_url = server->data; - size_t len; - - /* print server + filename into a buffer */ - len = strlen(server_url) + strlen(payload->remote_name) + 2; - MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - snprintf(payload->fileurl, len, "%s/%s", server_url, payload->remote_name); - payload->handle = handle; - payload->allow_resume = 1; - - ret = _alpm_download(payload, cachedir, NULL); - if(ret != -1) { - break; - } - } - if(ret == -1) { - errors++; - _alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files from %s\n"), - current->treename); - } + EVENT(handle, ALPM_EVENT_RETRIEVE_START, NULL, NULL); + for(i = files; i; i = i->next) { + if(download_single_file(handle, i->data, cachedir) == -1) { + errors++; + _alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files\n")); } - - alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_reset); - FREELIST(files); } } - for(j = handle->trans->add; j; j = j->next) { - alpm_pkg_t *pkg = j->data; +finish: + if(files) { + alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_reset); + FREELIST(files); + } + + for(i = handle->trans->add; i; i = i->next) { + alpm_pkg_t *pkg = i->data; pkg->infolevel &= ~INFRQ_DSIZE; pkg->download_size = 0; } diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index fbb320ef..cbc5bdfb 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -24,20 +24,14 @@ #include "config.h" -#include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <string.h> #include <unistd.h> #include <ctype.h> #include <dirent.h> -#include <fcntl.h> #include <time.h> #include <syslog.h> #include <errno.h> #include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> #include <sys/wait.h> #include <locale.h> /* setlocale */ @@ -131,48 +125,50 @@ int _alpm_makepath_mode(const char *path, mode_t mode) int _alpm_copyfile(const char *src, const char *dest) { - FILE *in, *out; - size_t len; char *buf; - int ret = 0; + int in, out, ret = 1; + ssize_t nread; + struct stat st; - in = fopen(src, "rb"); - if(in == NULL) { - return 1; - } - out = fopen(dest, "wb"); - if(out == NULL) { - fclose(in); - return 1; - } + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, ret = 1; goto cleanup); + OPEN(in, src, O_RDONLY); + do { + out = open(dest, O_WRONLY | O_CREAT, 0000); + } while(out == -1 && errno == EINTR); + if(in < 0 || out < 0) { + goto cleanup; + } - /* do the actual file copy */ - while((len = fread(buf, 1, ALPM_BUFFER_SIZE, in))) { - size_t nwritten = 0; - nwritten = fwrite(buf, 1, len, out); - if((nwritten != len) || ferror(out)) { - ret = -1; - goto cleanup; - } + if(fstat(in, &st) || fchmod(out, st.st_mode)) { + goto cleanup; } - /* chmod dest to permissions of src, as long as it is not a symlink */ - struct stat statbuf; - if(!stat(src, &statbuf)) { - if(! S_ISLNK(statbuf.st_mode)) { - fchmod(fileno(out), statbuf.st_mode); + /* do the actual file copy */ + while((nread = read(in, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + ssize_t nwrite = 0; + if(nread < 0) { + continue; } - } else { - /* stat was unsuccessful */ - ret = 1; + do { + nwrite = write(out, buf + nwrite, nread); + if(nwrite >= 0) { + nread -= nwrite; + } else if(errno != EINTR) { + goto cleanup; + } + } while(nread > 0); } + ret = 0; cleanup: - fclose(in); - fclose(out); free(buf); + if(in >= 0) { + CLOSE(in); + } + if(out >= 0) { + CLOSE(out); + } return ret; } @@ -295,9 +291,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, oldmask = umask(0022); /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -311,18 +305,11 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, } while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { - const struct stat *st; - const char *entryname; /* the name of the file in the archive */ + const char *entryname; + mode_t mode; - st = archive_entry_stat(entry); entryname = archive_entry_pathname(entry); - if(S_ISREG(st->st_mode)) { - archive_entry_set_perm(entry, 0644); - } else if(S_ISDIR(st->st_mode)) { - archive_entry_set_perm(entry, 0755); - } - /* If specific files were requested, skip entries that don't match. */ if(list) { char *entry_prefix = strdup(entryname); @@ -343,6 +330,13 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, } } + mode = archive_entry_mode(entry); + if(S_ISREG(mode)) { + archive_entry_set_perm(entry, 0644); + } else if(S_ISDIR(mode)) { + archive_entry_set_perm(entry, 0755); + } + /* Extract the archive entry. */ int readret = archive_read_extract(_archive, entry, 0); if(readret == ARCHIVE_WARN) { @@ -369,7 +363,7 @@ cleanup: _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } return ret; @@ -498,9 +492,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] int retval = 0; /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -534,12 +526,12 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] if(pid == 0) { /* this code runs for the child only (the actual chroot/exec) */ - close(1); - close(2); + CLOSE(1); + CLOSE(2); while(dup2(pipefd[1], 1) == -1 && errno == EINTR); while(dup2(pipefd[1], 2) == -1 && errno == EINTR); - close(pipefd[0]); - close(pipefd[1]); + CLOSE(pipefd[0]); + CLOSE(pipefd[1]); /* use fprintf instead of _alpm_log to send output through the parent */ if(chroot(handle->root) != 0) { @@ -553,6 +545,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] } umask(0022); execv(path, argv); + /* execv only returns if there was an error */ fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno)); exit(1); } else { @@ -560,10 +553,10 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] int status; FILE *pipe_file; - close(pipefd[1]); + CLOSE(pipefd[1]); pipe_file = fdopen(pipefd[0], "r"); if(pipe_file == NULL) { - close(pipefd[0]); + CLOSE(pipefd[0]); retval = 1; } else { while(!feof(pipe_file)) { @@ -605,7 +598,7 @@ cleanup: _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } return retval; @@ -741,49 +734,51 @@ int _alpm_lstat(const char *path, struct stat *buf) #ifdef HAVE_LIBSSL static int md5_file(const char *path, unsigned char output[16]) { - FILE *f; - size_t n; MD5_CTX ctx; unsigned char *buf; + ssize_t n; + int fd; - CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - if((f = fopen(path, "rb")) == NULL) { + OPEN(fd, path, O_RDONLY); + if(fd < 0) { free(buf); return 1; } MD5_Init(&ctx); - while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { + while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + if(n < 0) { + continue; + } MD5_Update(&ctx, buf, n); } - MD5_Final(output, &ctx); - - memset(&ctx, 0, sizeof(MD5_CTX)); + CLOSE(fd); free(buf); - if(ferror(f) != 0) { - fclose(f); + if(n < 0) { return 2; } - fclose(f); + MD5_Final(output, &ctx); return 0; } /* third param is so we match the PolarSSL definition */ static int sha2_file(const char *path, unsigned char output[32], int is224) { - FILE *f; - size_t n; SHA256_CTX ctx; unsigned char *buf; + ssize_t n; + int fd; - CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - if((f = fopen(path, "rb")) == NULL) { + OPEN(fd, path, O_RDONLY); + if(fd < 0) { free(buf); return 1; } @@ -794,7 +789,10 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) SHA256_Init(&ctx); } - while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { + while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + if(n < 0) { + continue; + } if(is224) { SHA224_Update(&ctx, buf, n); } else { @@ -802,25 +800,24 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) } } - if(is224) { - SHA224_Final(output, &ctx); - } else { - SHA256_Final(output, &ctx); - } - - memset(&ctx, 0, sizeof(SHA256_CTX)); + CLOSE(fd); free(buf); - if(ferror(f) != 0) { - fclose(f); + if(n < 0) { return 2; } - fclose(f); + if(is224) { + SHA224_Final(output, &ctx); + } else { + SHA256_Final(output, &ctx); + } return 0; } #endif +static const char *hex_digits = "0123456789abcdef"; + /** Get the md5 sum of file. * @param filename name of the file * @return the checksum on success, NULL on error @@ -834,8 +831,7 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename) ASSERT(filename != NULL, return NULL); - /* allocate 32 chars plus 1 for null */ - CALLOC(md5sum, 33, sizeof(char), return NULL); + MALLOC(md5sum, (size_t)33, return NULL); /* defined above for OpenSSL, otherwise defined in md5.h */ ret = md5_file(filename, output); @@ -846,10 +842,12 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename) /* Convert the result to something readable */ for (i = 0; i < 16; i++) { - /* sprintf is acceptable here because we know our output */ - sprintf(md5sum +(i * 2), "%02x", output[i]); + int pos = i * 2; + /* high 4 bits are first digit, low 4 are second */ + md5sum[pos] = hex_digits[output[i] >> 4]; + md5sum[pos + 1] = hex_digits[output[i] & 0x0f]; } - + md5sum[32] = '\0'; return md5sum; } @@ -866,8 +864,7 @@ char SYMEXPORT *alpm_compute_sha256sum(const char *filename) ASSERT(filename != NULL, return NULL); - /* allocate 64 chars plus 1 for null */ - CALLOC(sha256sum, 65, sizeof(char), return NULL); + MALLOC(sha256sum, (size_t)65, return NULL); /* defined above for OpenSSL, otherwise defined in sha2.h */ ret = sha2_file(filename, output, 0); @@ -878,10 +875,12 @@ char SYMEXPORT *alpm_compute_sha256sum(const char *filename) /* Convert the result to something readable */ for (i = 0; i < 32; i++) { - /* sprintf is acceptable here because we know our output */ - sprintf(sha256sum +(i * 2), "%02x", output[i]); + int pos = i * 2; + /* high 4 bits are first digit, low 4 are second */ + sha256sum[pos] = hex_digits[output[i] >> 4]; + sha256sum[pos + 1] = hex_digits[output[i] & 0x0f]; } - + sha256sum[64] = '\0'; return sha256sum; } @@ -914,16 +913,16 @@ int _alpm_test_checksum(const char *filepath, const char *expected, /* Note: does NOT handle sparse files on purpose for speed. */ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) { - char *i = NULL; - int64_t offset; - int done = 0; - /* ensure we start populating our line buffer at the beginning */ b->line_offset = b->line; while(1) { + size_t block_remaining; + char *eol; + /* have we processed this entire block? */ if(b->block + b->block_size == b->block_offset) { + int64_t offset; if(b->ret == ARCHIVE_EOF) { /* reached end of archive on the last read, now we are out of data */ goto cleanup; @@ -933,20 +932,20 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) b->ret = archive_read_data_block(a, (void *)&b->block, &b->block_size, &offset); b->block_offset = b->block; + block_remaining = b->block_size; /* error, cleanup */ if(b->ret < ARCHIVE_OK) { goto cleanup; } + } else { + block_remaining = b->block + b->block_size - b->block_offset; } - /* loop through the block looking for EOL characters */ - for(i = b->block_offset; i < (b->block + b->block_size); i++) { - /* check if read value was null or newline */ - if(*i == '\0' || *i == '\n') { - done = 1; - break; - } + /* look through the block looking for EOL characters */ + eol = memchr(b->block_offset, '\n', block_remaining); + if(!eol) { + eol = memchr(b->block_offset, '\0', block_remaining); } /* allocate our buffer, or ensure our existing one is big enough */ @@ -956,8 +955,10 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) b->line_size = b->block_size + 1; b->line_offset = b->line; } else { - size_t needed = (size_t)((b->line_offset - b->line) - + (i - b->block_offset) + 1); + /* note: we know eol > b->block_offset and b->line_offset > b->line, + * so we know the result is unsigned and can fit in size_t */ + size_t new = eol ? (size_t)(eol - b->block_offset) : block_remaining; + size_t needed = (size_t)((b->line_offset - b->line) + new + 1); if(needed > b->max_line_size) { b->ret = -ERANGE; goto cleanup; @@ -974,11 +975,11 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) } } - if(done) { - size_t len = (size_t)(i - b->block_offset); + if(eol) { + size_t len = (size_t)(eol - b->block_offset); memcpy(b->line_offset, b->block_offset, len); b->line_offset[len] = '\0'; - b->block_offset = ++i; + b->block_offset = eol + 1; /* this is the main return point; from here you can read b->line */ return ARCHIVE_OK; } else { @@ -986,7 +987,7 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) size_t len = (size_t)(b->block + b->block_size - b->block_offset); memcpy(b->line_offset, b->block_offset, len); b->line_offset += len; - b->block_offset = i; + b->block_offset = b->block + b->block_size; /* there was no new data, return what is left; saved ARCHIVE_EOF will be * returned on next call */ if(len == 0) { @@ -1103,8 +1104,12 @@ off_t _alpm_strtoofft(const char *line) return (off_t)result; } -time_t _alpm_parsedate(const char *line) +alpm_time_t _alpm_parsedate(const char *line) { + char *end; + long long result; + errno = 0; + if(isalpha((unsigned char)line[0])) { /* initialize to null in case of failure */ struct tm tmp_tm; @@ -1112,9 +1117,24 @@ time_t _alpm_parsedate(const char *line) setlocale(LC_TIME, "C"); strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); setlocale(LC_TIME, ""); - return mktime(&tmp_tm); + return (alpm_time_t)mktime(&tmp_tm); } - return (time_t)atol(line); + + result = strtoll(line, &end, 10); + if (result == 0 && end == line) { + /* line was not a number */ + errno = EINVAL; + return 0; + } else if (errno == ERANGE) { + /* line does not fit in long long */ + return 0; + } else if (*end) { + /* line began with a number but has junk left over at the end */ + errno = EINVAL; + return 0; + } + + return (alpm_time_t)result; } /** diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 26fa9044..61dc8e55 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -35,11 +35,13 @@ #include <string.h> #include <stdarg.h> #include <stddef.h> /* size_t */ -#include <time.h> +#include <sys/types.h> #include <sys/stat.h> /* struct stat */ -#include <archive.h> /* struct archive */ #include <math.h> /* fabs */ #include <float.h> /* DBL_EPSILON */ +#include <fcntl.h> /* open, close */ + +#include <archive.h> /* struct archive */ #ifdef ENABLE_NLS #include <libintl.h> /* here so it doesn't need to be included elsewhere */ @@ -51,8 +53,8 @@ #define ALLOC_FAIL(s) do { fprintf(stderr, "alloc failure: could not allocate %zd bytes\n", s); } while(0) -#define MALLOC(p, s, action) do { p = calloc(1, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) -#define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) +#define MALLOC(p, s, action) do { p = malloc(s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) +#define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(l * s); action; } } while(0) /* This strdup macro is NULL safe- copying NULL will yield NULL */ #define STRDUP(r, s, action) do { if(s != NULL) { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) #define STRNDUP(r, s, l, action) do { if(s != NULL) { r = strndup(s, l); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) @@ -82,6 +84,13 @@ #define ALPM_BUFFER_SIZE 8192 #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define OPEN(fd, path, flags) do { fd = open(path, flags | O_BINARY); } while(fd == -1 && errno == EINTR) +#define CLOSE(fd) do { int ret; do { ret = close(fd); } while(ret == -1 && errno == EINTR); } while(0) + /** * Used as a buffer/state holder for _alpm_archive_fgets(). */ @@ -127,7 +136,7 @@ int _alpm_splitname(const char *target, char **name, char **version, unsigned long *name_hash); unsigned long _alpm_hash_sdbm(const char *str); off_t _alpm_strtoofft(const char *line); -time_t _alpm_parsedate(const char *line); +alpm_time_t _alpm_parsedate(const char *line); int _alpm_raw_cmp(const char *first, const char *second); int _alpm_raw_ncmp(const char *first, const char *second, size_t max); int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int amode); |