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