summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libalpm/Makefile.am6
-rw-r--r--lib/libalpm/add.c205
-rw-r--r--lib/libalpm/alpm.c1
-rw-r--r--lib/libalpm/alpm.h121
-rw-r--r--lib/libalpm/alpm_list.c164
-rw-r--r--lib/libalpm/alpm_list.h4
-rw-r--r--lib/libalpm/be_files.c560
-rw-r--r--lib/libalpm/be_package.c285
-rw-r--r--lib/libalpm/cache.c89
-rw-r--r--lib/libalpm/conflict.c83
-rw-r--r--lib/libalpm/conflict.h17
-rw-r--r--lib/libalpm/db.c207
-rw-r--r--lib/libalpm/db.h12
-rw-r--r--lib/libalpm/delta.c323
-rw-r--r--lib/libalpm/delta.h33
-rw-r--r--lib/libalpm/deps.c243
-rw-r--r--lib/libalpm/deps.h32
-rw-r--r--lib/libalpm/dload.c463
-rw-r--r--lib/libalpm/dload.h (renamed from lib/libalpm/error.h)26
-rw-r--r--lib/libalpm/error.c62
-rw-r--r--lib/libalpm/graph.h56
-rw-r--r--lib/libalpm/group.c20
-rw-r--r--lib/libalpm/group.h12
-rw-r--r--lib/libalpm/handle.c35
-rw-r--r--lib/libalpm/handle.h3
-rw-r--r--lib/libalpm/log.c1
-rw-r--r--lib/libalpm/md5.c86
-rw-r--r--lib/libalpm/md5.h29
-rw-r--r--lib/libalpm/package.c589
-rw-r--r--lib/libalpm/package.h37
-rw-r--r--lib/libalpm/po/POTFILES.in2
-rw-r--r--lib/libalpm/remove.c97
-rw-r--r--lib/libalpm/server.c469
-rw-r--r--lib/libalpm/server.h46
-rw-r--r--lib/libalpm/sync.c1039
-rw-r--r--lib/libalpm/sync.h6
-rw-r--r--lib/libalpm/trans.c25
-rw-r--r--lib/libalpm/trans.h1
-rw-r--r--lib/libalpm/util.c134
-rw-r--r--lib/libalpm/util.h12
40 files changed, 2772 insertions, 2863 deletions
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am
index 14d42a0c..871855ef 100644
--- a/lib/libalpm/Makefile.am
+++ b/lib/libalpm/Makefile.am
@@ -26,19 +26,21 @@ libalpm_la_SOURCES = \
alpm_list.h alpm_list.c \
backup.h backup.c \
be_files.c \
+ be_package.c \
cache.h cache.c \
conflict.h conflict.c \
db.h db.c \
delta.h delta.c \
deps.h deps.c \
- error.h error.c \
+ dload.h dload.c \
+ error.c \
+ graph.h \
group.h group.c \
handle.h handle.c \
log.h log.c \
md5.h md5.c \
package.h package.c \
remove.h remove.c \
- server.h server.c \
sync.h sync.c \
trans.h trans.c \
util.h util.c
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index 0a1a1924..c5454bab 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -37,7 +37,6 @@
#include "alpm_list.h"
#include "trans.h"
#include "util.h"
-#include "error.h"
#include "cache.h"
#include "log.h"
#include "backup.h"
@@ -68,41 +67,25 @@ int _alpm_add_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name)
pkgname = alpm_pkg_get_name(pkg);
pkgver = alpm_pkg_get_version(pkg);
- if(trans->type != PM_TRANS_TYPE_UPGRADE) {
- /* only install this package if it is not already installed */
- if(_alpm_db_get_pkgfromcache(db, pkgname)) {
- pm_errno = PM_ERR_PKG_INSTALLED;
- goto error;
- }
- }
-
/* check if an older version of said package is already in transaction
* packages. if so, replace it in the list */
for(i = trans->packages; i; i = i->next) {
- pmpkg_t *pkg = i->data;
- if(strcmp(pkg->name, pkgname) == 0) {
- if(_alpm_versioncmp(pkg->version, pkgver) < 0) {
- pmpkg_t *newpkg;
+ pmpkg_t *transpkg = i->data;
+ if(strcmp(transpkg->name, pkgname) == 0) {
+ if(alpm_pkg_vercmp(transpkg->version, pkgver) < 0) {
_alpm_log(PM_LOG_WARNING, _("replacing older version %s-%s by %s in target list\n"),
- pkg->name, pkg->version, pkgver);
- if((newpkg = _alpm_pkg_load(name, 1)) == NULL) {
- /* pm_errno is already set by pkg_load() */
- goto error;
- }
+ transpkg->name, transpkg->version, pkgver);
_alpm_pkg_free(i->data);
- i->data = newpkg;
+ i->data = pkg;
} else {
- _alpm_log(PM_LOG_WARNING, _("newer version %s-%s is in the target list -- skipping\n"),
- pkg->name, pkg->version);
+ _alpm_log(PM_LOG_WARNING, _("skipping %s-%s because newer version %s is in the target list\n"),
+ pkgname, pkgver, transpkg->version);
+ _alpm_pkg_free(pkg);
}
return(0);
}
}
- if(trans->flags & PM_TRANS_FLAG_ALLDEPS) {
- pkg->reason = PM_PKG_REASON_DEPEND;
- }
-
/* add the package to the transaction */
trans->packages = alpm_list_add(trans->packages, pkg);
@@ -113,15 +96,6 @@ error:
return(-1);
}
-
-/* This is still messy. We have a lot of compare functions, and we should
- * try to consolidate them as much as we can (between add and sync) */
-/*static int deppkg_cmp(const void *p1, const void *p2)
-{
- return(strcmp(((pmdepmissing_t *)p1)->target,
- ((pmdepmissing_t *)p2)->target));
-}*/
-
int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
{
alpm_list_t *lp = NULL;
@@ -138,12 +112,13 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
/* look for unsatisfied dependencies */
_alpm_log(PM_LOG_DEBUG, "looking for unsatisfied dependencies\n");
- lp = alpm_checkdeps(db, trans->type == PM_TRANS_TYPE_UPGRADE, NULL, trans->packages);
+ lp = alpm_checkdeps(db, 1, NULL, trans->packages);
if(lp != NULL) {
if(data) {
*data = lp;
} else {
- FREELIST(lp);
+ alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
+ alpm_list_free(lp);
}
RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1);
}
@@ -167,7 +142,7 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
_alpm_log(PM_LOG_ERROR, _("you cannot install two conflicting packages at the same time\n"));
}
if(outer) {
- _alpm_log(PM_LOG_ERROR, _("replacing packages with -A and -U is not supported yet\n"));
+ _alpm_log(PM_LOG_ERROR, _("replacing packages with -U is not supported yet\n"));
_alpm_log(PM_LOG_ERROR, _("you can replace packages manually using -Rd and -U\n"));
}
RET_ERR(PM_ERR_CONFLICTING_DEPS, -1);
@@ -175,7 +150,7 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
/* re-order w.r.t. dependencies */
_alpm_log(PM_LOG_DEBUG, "sorting by dependencies\n");
- lp = _alpm_sortbydeps(trans->packages, PM_TRANS_TYPE_ADD);
+ lp = _alpm_sortbydeps(trans->packages, 0);
/* free the old alltargs */
alpm_list_free(trans->packages);
trans->packages = lp;
@@ -193,7 +168,8 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
if(data) {
*data = lp;
} else {
- FREELIST(lp);
+ alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_fileconflict_free);
+ alpm_list_free(lp);
}
RET_ERR(PM_ERR_FILE_CONFLICTS, -1);
}
@@ -210,6 +186,9 @@ static int upgrade_remove(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *trans, pm
* with the type PM_TRANS_TYPE_REMOVEUPGRADE. TODO: kill this weird
* behavior. */
pmtrans_t *tr = _alpm_trans_new();
+
+ ALPM_LOG_FUNC;
+
_alpm_log(PM_LOG_DEBUG, "removing old package first (%s-%s)\n",
oldpkg->name, oldpkg->version);
@@ -290,17 +269,18 @@ static int extract_single_file(struct archive *archive,
struct archive_entry *entry, pmpkg_t *newpkg, pmpkg_t *oldpkg,
pmtrans_t *trans, pmdb_t *db)
{
- char entryname[PATH_MAX]; /* the name of the file in the archive */
+ const char *entryname;
mode_t entrymode;
char filename[PATH_MAX]; /* the actual file we're extracting */
int needbackup = 0, notouch = 0;
char *hash_orig = NULL;
+ char *entryname_orig = NULL;
const int archive_flags = ARCHIVE_EXTRACT_OWNER |
ARCHIVE_EXTRACT_PERM |
ARCHIVE_EXTRACT_TIME;
int errors = 0;
- strncpy(entryname, archive_entry_pathname(entry), PATH_MAX);
+ entryname = archive_entry_pathname(entry);
entrymode = archive_entry_mode(entry);
memset(filename, 0, PATH_MAX); /* just to be sure */
@@ -338,7 +318,8 @@ static int extract_single_file(struct archive *archive,
/* if a file is in the add skiplist we never extract it */
if(alpm_list_find_str(trans->skip_add, filename)) {
- _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_add, skipping extraction\n", entryname);
+ _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_add, skipping extraction\n",
+ entryname);
archive_read_data_skip(archive);
return(0);
}
@@ -437,7 +418,7 @@ static int extract_single_file(struct archive *archive,
/* if we force hash_orig to be non-NULL retroactive backup works */
if(needbackup && !hash_orig) {
- hash_orig = strdup("");
+ STRDUP(hash_orig, "", RET_ERR(PM_ERR_MEMORY, -1));
}
}
}
@@ -445,34 +426,35 @@ static int extract_single_file(struct archive *archive,
/* case 5,8: don't need to do anything special */
}
+ /* we need access to the original entryname later after calls to
+ * archive_entry_set_pathname(), so we need to dupe it and free() later */
+ STRDUP(entryname_orig, entryname, RET_ERR(PM_ERR_MEMORY, -1));
+
if(needbackup) {
- char *tempfile;
+ char checkfile[PATH_MAX];
char *hash_local = NULL, *hash_pkg = NULL;
- int fd;
+ int ret;
- /* extract the package's version to a temporary file and checksum it */
- tempfile = strdup("/tmp/alpm_XXXXXX");
- fd = mkstemp(tempfile);
+ snprintf(checkfile, PATH_MAX, "%s.paccheck", filename);
+ archive_entry_set_pathname(entry, checkfile);
- int ret = archive_read_data_into_fd(archive, fd);
- close(fd);
+ ret = archive_read_extract(archive, entry, archive_flags);
if(ret == ARCHIVE_WARN) {
/* operation succeeded but a non-critical error was encountered */
_alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
- entryname, archive_error_string(archive));
+ entryname_orig, archive_error_string(archive));
} else if(ret != ARCHIVE_OK) {
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
- entryname, archive_error_string(archive));
+ entryname_orig, archive_error_string(archive));
alpm_logaction("error: could not extract %s (%s)\n",
- entryname, archive_error_string(archive));
- unlink(tempfile);
- FREE(tempfile);
+ entryname_orig, archive_error_string(archive));
FREE(hash_orig);
+ FREE(entryname_orig);
return(1);
}
hash_local = alpm_get_md5sum(filename);
- hash_pkg = alpm_get_md5sum(tempfile);
+ hash_pkg = alpm_get_md5sum(checkfile);
/* append the new md5 hash to it's respective entry
* in newpkg's backup (it will be the new orginal) */
@@ -480,16 +462,13 @@ static int extract_single_file(struct archive *archive,
for(backups = alpm_pkg_get_backup(newpkg); backups;
backups = alpm_list_next(backups)) {
char *oldbackup = alpm_list_getdata(backups);
- if(!oldbackup || strcmp(oldbackup, entryname) != 0) {
+ if(!oldbackup || strcmp(oldbackup, entryname_orig) != 0) {
continue;
}
char *backup = NULL;
/* length is tab char, null byte and MD5 (32 char) */
- int backup_len = strlen(oldbackup) + 34;
- backup = malloc(backup_len);
- if(!backup) {
- RET_ERR(PM_ERR_MEMORY, -1);
- }
+ size_t backup_len = strlen(oldbackup) + 34;
+ MALLOC(backup, backup_len, RET_ERR(PM_ERR_MEMORY, -1));
sprintf(backup, "%s\t%s", oldbackup, hash_pkg);
backup[backup_len-1] = '\0';
@@ -497,7 +476,7 @@ static int extract_single_file(struct archive *archive,
backups->data = backup;
}
- _alpm_log(PM_LOG_DEBUG, "checking hashes for %s\n", entryname);
+ _alpm_log(PM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig);
_alpm_log(PM_LOG_DEBUG, "current: %s\n", hash_local);
_alpm_log(PM_LOG_DEBUG, "new: %s\n", hash_pkg);
_alpm_log(PM_LOG_DEBUG, "original: %s\n", hash_orig);
@@ -511,19 +490,20 @@ static int extract_single_file(struct archive *archive,
/* move the existing file to the "pacorig" */
if(rename(filename, newpath)) {
- archive_entry_set_pathname(entry, filename);
- _alpm_log(PM_LOG_ERROR, _("could not rename %s (%s)\n"), filename, strerror(errno));
- alpm_logaction("error: could not rename %s (%s)\n", filename, strerror(errno));
+ _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
+ filename, newpath, strerror(errno));
+ alpm_logaction("error: could not rename %s to %s (%s)\n",
+ filename, newpath, strerror(errno));
errors++;
} else {
- /* copy the tempfile we extracted to the real path */
- if(_alpm_copyfile(tempfile, filename)) {
- archive_entry_set_pathname(entry, filename);
- _alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), filename, strerror(errno));
- alpm_logaction("error: could not copy tempfile to %s (%s)\n", filename, strerror(errno));
+ /* rename the file we extracted to the real name */
+ if(rename(checkfile, filename)) {
+ _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
+ checkfile, filename, strerror(errno));
+ alpm_logaction("error: could not rename %s to %s (%s)\n",
+ checkfile, filename, strerror(errno));
errors++;
} else {
- archive_entry_set_pathname(entry, filename);
_alpm_log(PM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath);
alpm_logaction("warning: %s saved as %s\n", filename, newpath);
}
@@ -536,38 +516,48 @@ static int extract_single_file(struct archive *archive,
/* installed file has NOT been changed by user */
if(strcmp(hash_orig, hash_pkg) != 0) {
_alpm_log(PM_LOG_DEBUG, "action: installing new file: %s\n",
- entryname);
+ entryname_orig);
- if(_alpm_copyfile(tempfile, filename)) {
- _alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), filename, strerror(errno));
+ if(rename(checkfile, filename)) {
+ _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
+ checkfile, filename, strerror(errno));
+ alpm_logaction("error: could not rename %s to %s (%s)\n",
+ checkfile, filename, strerror(errno));
errors++;
}
- archive_entry_set_pathname(entry, filename);
} else {
/* there's no sense in installing the same file twice, install
* ONLY is the original and package hashes differ */
_alpm_log(PM_LOG_DEBUG, "action: leaving existing file in place\n");
+ unlink(checkfile);
}
} else if(strcmp(hash_orig, hash_pkg) == 0) {
/* originally installed file and new file are the same - this
* implies the case above failed - i.e. the file was changed by a
* user */
_alpm_log(PM_LOG_DEBUG, "action: leaving existing file in place\n");
+ unlink(checkfile);
} else if(strcmp(hash_local, hash_pkg) == 0) {
/* this would be magical. The above two cases failed, but the
* user changes just so happened to make the new file exactly the
* same as the one in the package... skip it */
_alpm_log(PM_LOG_DEBUG, "action: leaving existing file in place\n");
+ unlink(checkfile);
} else {
char newpath[PATH_MAX];
- _alpm_log(PM_LOG_DEBUG, "action: keeping current file and installing new one with .pacnew ending\n");
+ _alpm_log(PM_LOG_DEBUG, "action: keeping current file and installing"
+ " new one with .pacnew ending\n");
snprintf(newpath, PATH_MAX, "%s.pacnew", filename);
- if(_alpm_copyfile(tempfile, newpath)) {
- _alpm_log(PM_LOG_ERROR, _("could not install %s as %s: %s\n"), filename, newpath, strerror(errno));
- alpm_logaction("error: could not install %s as %s: %s\n", filename, newpath, strerror(errno));
+ if(rename(checkfile, newpath)) {
+ _alpm_log(PM_LOG_ERROR, _("could not install %s as %s (%s)\n"),
+ filename, newpath, strerror(errno));
+ alpm_logaction("error: could not install %s as %s (%s)\n",
+ filename, newpath, strerror(errno));
} else {
- _alpm_log(PM_LOG_WARNING, _("%s installed as %s\n"), filename, newpath);
- alpm_logaction("warning: %s installed as %s\n", filename, newpath);
+ _alpm_log(PM_LOG_WARNING, _("%s installed as %s\n"),
+ filename, newpath);
+ alpm_logaction("warning: %s installed as %s\n",
+ filename, newpath);
}
}
}
@@ -575,9 +565,9 @@ static int extract_single_file(struct archive *archive,
FREE(hash_local);
FREE(hash_pkg);
FREE(hash_orig);
- unlink(tempfile);
- FREE(tempfile);
} else {
+ int ret;
+
/* we didn't need a backup */
if(notouch) {
/* change the path to a .pacnew extension */
@@ -598,16 +588,17 @@ static int extract_single_file(struct archive *archive,
archive_entry_set_pathname(entry, filename);
- int ret = archive_read_extract(archive, entry, archive_flags);
+ ret = archive_read_extract(archive, entry, archive_flags);
if(ret == ARCHIVE_WARN) {
/* operation succeeded but a non-critical error was encountered */
_alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
- entryname, archive_error_string(archive));
+ entryname_orig, archive_error_string(archive));
} else if(ret != ARCHIVE_OK) {
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
- entryname, archive_error_string(archive));
+ entryname_orig, archive_error_string(archive));
alpm_logaction("error: could not extract %s (%s)\n",
- entryname, archive_error_string(archive));
+ entryname_orig, archive_error_string(archive));
+ FREE(entryname_orig);
return(1);
}
@@ -617,18 +608,15 @@ static int extract_single_file(struct archive *archive,
char *backup = NULL, *hash = NULL;
char *oldbackup = alpm_list_getdata(b);
/* length is tab char, null byte and MD5 (32 char) */
- int backup_len = strlen(oldbackup) + 34;
+ size_t backup_len = strlen(oldbackup) + 34;
- if(!oldbackup || strcmp(oldbackup, entryname) != 0) {
+ if(!oldbackup || strcmp(oldbackup, entryname_orig) != 0) {
continue;
}
_alpm_log(PM_LOG_DEBUG, "appending backup entry for %s\n", filename);
hash = alpm_get_md5sum(filename);
- backup = malloc(backup_len);
- if(!backup) {
- RET_ERR(PM_ERR_MEMORY, -1);
- }
+ MALLOC(backup, backup_len, RET_ERR(PM_ERR_MEMORY, -1));
sprintf(backup, "%s\t%s", oldbackup, hash);
backup[backup_len-1] = '\0';
@@ -637,6 +625,7 @@ static int extract_single_file(struct archive *archive,
b->data = backup;
}
}
+ FREE(entryname_orig);
return(errors);
}
@@ -644,14 +633,13 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
pmtrans_t *trans, pmdb_t *db)
{
int i, ret = 0, errors = 0;
- struct archive *archive;
- struct archive_entry *entry;
- char cwd[PATH_MAX] = "";
char scriptlet[PATH_MAX+1];
int is_upgrade = 0;
double percent = 0.0;
pmpkg_t *oldpkg = NULL;
+ ALPM_LOG_FUNC;
+
snprintf(scriptlet, PATH_MAX, "%s%s-%s/install", db->path,
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
@@ -666,12 +654,8 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
/* we'll need to save some record for backup checks later */
oldpkg = _alpm_pkg_dup(local);
- /* copy over the install reason (unless alldeps is set) */
- if(trans->flags & PM_TRANS_FLAG_ALLDEPS) {
- newpkg->reason = PM_PKG_REASON_DEPEND;
- } else {
+ /* copy over the install reason */
newpkg->reason = alpm_pkg_get_reason(local);
- }
/* pre_upgrade scriptlet */
if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) {
@@ -692,6 +676,13 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
}
}
+ /* we override any pre-set reason if we have alldeps or allexplicit set */
+ if(trans->flags & PM_TRANS_FLAG_ALLDEPS) {
+ newpkg->reason = PM_PKG_REASON_DEPEND;
+ } else if(trans->flags & PM_TRANS_FLAG_ALLEXPLICIT) {
+ newpkg->reason = PM_PKG_REASON_EXPLICIT;
+ }
+
if(oldpkg) {
/* set up fake remove transaction */
int ret = upgrade_remove(oldpkg, newpkg, trans, db);
@@ -701,15 +692,20 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
}
if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {
+ struct archive *archive;
+ struct archive_entry *entry;
+ char cwd[PATH_MAX] = "";
+
_alpm_log(PM_LOG_DEBUG, "extracting files\n");
if ((archive = archive_read_new()) == NULL) {
- RET_ERR(PM_ERR_LIBARCHIVE_ERROR, -1);
+ RET_ERR(PM_ERR_LIBARCHIVE, -1);
}
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
+ _alpm_log(PM_LOG_DEBUG, "archive: %s\n", newpkg->origin_data.file);
if(archive_read_open_filename(archive, newpkg->origin_data.file,
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
RET_ERR(PM_ERR_PKG_OPEN, -1);
@@ -810,7 +806,6 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START,
alpm_pkg_get_name(newpkg), 100, pkg_count, pkg_current);
}
- EVENT(trans, PM_TRANS_EVT_EXTRACT_DONE, NULL, NULL);
/* run the post-install script if it exists */
if(alpm_pkg_has_scriptlet(newpkg)
@@ -850,7 +845,7 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
return(0);
}
- pkg_count = alpm_list_count(trans->targets);
+ pkg_count = alpm_list_count(trans->packages);
pkg_current = 1;
/* loop through our package list adding/upgrading one at a time */
diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c
index fb19d076..ee29d534 100644
--- a/lib/libalpm/alpm.c
+++ b/lib/libalpm/alpm.c
@@ -25,7 +25,6 @@
/* libalpm */
#include "alpm.h"
#include "alpm_list.h"
-#include "error.h"
#include "handle.h"
#include "util.h"
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 96b63ca6..62a517b4 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -45,14 +45,12 @@ typedef struct __pmdb_t pmdb_t;
typedef struct __pmpkg_t pmpkg_t;
typedef struct __pmdelta_t pmdelta_t;
typedef struct __pmgrp_t pmgrp_t;
-typedef struct __pmserver_t pmserver_t;
typedef struct __pmtrans_t pmtrans_t;
typedef struct __pmsyncpkg_t pmsyncpkg_t;
typedef struct __pmdepend_t pmdepend_t;
typedef struct __pmdepmissing_t pmdepmissing_t;
typedef struct __pmconflict_t pmconflict_t;
typedef struct __pmfileconflict_t pmfileconflict_t;
-typedef struct __pmgraph_t pmgraph_t;
/*
* Library
@@ -81,8 +79,7 @@ int alpm_logaction(char *fmt, ...);
* Downloading
*/
-typedef void (*alpm_cb_download)(const char *filename, int file_xfered,
- int file_total, int list_xfered, int list_total);
+typedef void (*alpm_cb_download)(const char *filename, int xfered, int total);
/*
* Options
@@ -170,7 +167,6 @@ int alpm_db_update(int level, pmdb_t *db);
pmpkg_t *alpm_db_get_pkg(pmdb_t *db, const char *name);
alpm_list_t *alpm_db_getpkgcache(pmdb_t *db);
-alpm_list_t *alpm_db_whatprovides(pmdb_t *db, const char *name);
pmgrp_t *alpm_db_readgrp(pmdb_t *db, const char *name);
alpm_list_t *alpm_db_getgrpcache(pmdb_t *db);
@@ -192,7 +188,7 @@ int alpm_pkg_load(const char *filename, unsigned short full, pmpkg_t **pkg);
int alpm_pkg_free(pmpkg_t *pkg);
int alpm_pkg_checkmd5sum(pmpkg_t *pkg);
char *alpm_fetch_pkgurl(const char *url);
-int alpm_pkg_vercmp(const char *ver1, const char *ver2);
+int alpm_pkg_vercmp(const char *a, const char *b);
alpm_list_t *alpm_pkg_compute_requiredby(pmpkg_t *pkg);
const char *alpm_pkg_get_filename(pmpkg_t *pkg);
@@ -225,38 +221,33 @@ size_t alpm_pkg_changelog_read(void *ptr, size_t size,
int alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp);
unsigned short alpm_pkg_has_scriptlet(pmpkg_t *pkg);
-unsigned long alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local);
+unsigned long alpm_pkg_download_size(pmpkg_t *newpkg);
/*
* Deltas
*/
const char *alpm_delta_get_from(pmdelta_t *delta);
+const char *alpm_delta_get_from_md5sum(pmdelta_t *delta);
const char *alpm_delta_get_to(pmdelta_t *delta);
-unsigned long alpm_delta_get_size(pmdelta_t *delta);
+const char *alpm_delta_get_to_md5sum(pmdelta_t *delta);
const char *alpm_delta_get_filename(pmdelta_t *delta);
const char *alpm_delta_get_md5sum(pmdelta_t *delta);
+unsigned long alpm_delta_get_size(pmdelta_t *delta);
/*
* Groups
*/
const char *alpm_grp_get_name(const pmgrp_t *grp);
-const alpm_list_t *alpm_grp_get_pkgs(const pmgrp_t *grp);
+alpm_list_t *alpm_grp_get_pkgs(const pmgrp_t *grp);
/*
* Sync
*/
-/* Types */
-typedef enum _pmsynctype_t {
- PM_SYNC_TYPE_REPLACE = 1,
- PM_SYNC_TYPE_UPGRADE,
- PM_SYNC_TYPE_DEPEND
-} pmsynctype_t;
-
-pmsynctype_t alpm_sync_get_type(const pmsyncpkg_t *sync);
pmpkg_t *alpm_sync_get_pkg(const pmsyncpkg_t *sync);
-void *alpm_sync_get_data(const pmsyncpkg_t *sync);
+alpm_list_t *alpm_sync_get_removes(const pmsyncpkg_t *sync);
+pmpkg_t *alpm_sync_newversion(pmpkg_t *pkg, alpm_list_t *dbs_sync);
int alpm_sync_sysupgrade(pmdb_t *db_local,
alpm_list_t *dbs_sync, alpm_list_t **syncpkgs);
@@ -266,10 +257,9 @@ int alpm_sync_sysupgrade(pmdb_t *db_local,
/* Types */
typedef enum _pmtranstype_t {
- PM_TRANS_TYPE_ADD = 1,
+ PM_TRANS_TYPE_UPGRADE = 1,
PM_TRANS_TYPE_REMOVE,
PM_TRANS_TYPE_REMOVEUPGRADE,
- PM_TRANS_TYPE_UPGRADE,
PM_TRANS_TYPE_SYNC
} pmtranstype_t;
@@ -282,45 +272,103 @@ typedef enum _pmtransflag_t {
PM_TRANS_FLAG_CASCADE = 0x10,
PM_TRANS_FLAG_RECURSE = 0x20,
PM_TRANS_FLAG_DBONLY = 0x40,
- PM_TRANS_FLAG_DEPENDSONLY = 0x80,
+ /* 0x80 flag can go here */
PM_TRANS_FLAG_ALLDEPS = 0x100,
PM_TRANS_FLAG_DOWNLOADONLY = 0x200,
PM_TRANS_FLAG_NOSCRIPTLET = 0x400,
PM_TRANS_FLAG_NOCONFLICTS = 0x800,
PM_TRANS_FLAG_PRINTURIS = 0x1000,
- PM_TRANS_FLAG_NEEDED = 0x2000
+ PM_TRANS_FLAG_NEEDED = 0x2000,
+ PM_TRANS_FLAG_ALLEXPLICIT = 0x4000,
+ PM_TRANS_FLAG_UNNEEDED = 0x8000,
+ PM_TRANS_FLAG_RECURSEALL = 0x10000
} pmtransflag_t;
-/* Transaction Events */
+/**
+ * @addtogroup alpm_trans
+ * @{
+ */
+/**
+ * @brief Transaction events.
+ * NULL parameters are passed to in all events unless specified otherwise.
+ */
typedef enum _pmtransevt_t {
+ /** Dependencies will be computed for a package. */
PM_TRANS_EVT_CHECKDEPS_START = 1,
+ /** Dependencies were computed for a package. */
PM_TRANS_EVT_CHECKDEPS_DONE,
+ /** File conflicts will be computed for a package. */
PM_TRANS_EVT_FILECONFLICTS_START,
+ /** File conflicts were computed for a package. */
PM_TRANS_EVT_FILECONFLICTS_DONE,
+ /** Dependencies will be resolved for target package. */
PM_TRANS_EVT_RESOLVEDEPS_START,
+ /** Dependencies were resolved for target package. */
PM_TRANS_EVT_RESOLVEDEPS_DONE,
+ /** Inter-conflicts will be checked for target package. */
PM_TRANS_EVT_INTERCONFLICTS_START,
+ /** Inter-conflicts were checked for target package. */
PM_TRANS_EVT_INTERCONFLICTS_DONE,
+ /** Package will be installed.
+ * A pointer to the target package is passed to the callback.
+ */
PM_TRANS_EVT_ADD_START,
+ /** Package was installed.
+ * A pointer to the new package is passed to the callback.
+ */
PM_TRANS_EVT_ADD_DONE,
+ /** Package will be removed.
+ * A pointer to the target package is passed to the callback.
+ */
PM_TRANS_EVT_REMOVE_START,
+ /** Package was removed.
+ * A pointer to the removed package is passed to the callback.
+ */
PM_TRANS_EVT_REMOVE_DONE,
+ /** Package will be upgraded.
+ * A pointer to the upgraded package is passed to the callback.
+ */
PM_TRANS_EVT_UPGRADE_START,
+ /** Package was upgraded.
+ * A pointer to the new package, and a pointer to the old package is passed
+ * to the callback, respectively.
+ */
PM_TRANS_EVT_UPGRADE_DONE,
- PM_TRANS_EVT_EXTRACT_DONE,
+ /** Target package's integrity will be checked. */
PM_TRANS_EVT_INTEGRITY_START,
+ /** Target package's integrity was checked. */
PM_TRANS_EVT_INTEGRITY_DONE,
+ /** Target deltas's integrity will be checked. */
PM_TRANS_EVT_DELTA_INTEGRITY_START,
+ /** Target delta's integrity was checked. */
PM_TRANS_EVT_DELTA_INTEGRITY_DONE,
+ /** Deltas will be applied to packages. */
PM_TRANS_EVT_DELTA_PATCHES_START,
+ /** Deltas were applied to packages. */
PM_TRANS_EVT_DELTA_PATCHES_DONE,
+ /** Delta patch will be applied to target package.
+ * The filename of the package and the filename of the patch is passed to the
+ * callback.
+ */
PM_TRANS_EVT_DELTA_PATCH_START,
+ /** Delta patch was applied to target package. */
PM_TRANS_EVT_DELTA_PATCH_DONE,
+ /** Delta patch failed to apply to target package. */
PM_TRANS_EVT_DELTA_PATCH_FAILED,
+ /** Scriptlet has printed information.
+ * A line of text is passed to the callback.
+ */
PM_TRANS_EVT_SCRIPTLET_INFO,
+ /** Print URI.
+ * The database's URI and the package's filename are passed to the callback.
+ */
PM_TRANS_EVT_PRINTURI,
+ /** Files will be downloaded from a repository.
+ * The repository's tree name is passed to the callback.
+ */
PM_TRANS_EVT_RETRIEVE_START,
} pmtransevt_t;
+/*@}*/
/* Transaction Conversations (ie, questions) */
typedef enum _pmtransconv_t {
@@ -353,7 +401,6 @@ typedef void (*alpm_trans_cb_progress)(pmtransprog_t, const char *, int, int, in
pmtranstype_t alpm_trans_get_type();
unsigned int alpm_trans_get_flags();
-alpm_list_t * alpm_trans_get_targets();
alpm_list_t * alpm_trans_get_pkgs();
int alpm_trans_init(pmtranstype_t type, pmtransflag_t flags,
alpm_trans_cb_event cb_event, alpm_trans_cb_conv conv,
@@ -378,13 +425,17 @@ typedef enum _pmdepmod_t {
PM_DEP_MOD_LT
} pmdepmod_t;
-pmdepend_t *alpm_splitdep(const char *depstring);
int alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep);
alpm_list_t *alpm_checkdeps(pmdb_t *db, int reversedeps,
alpm_list_t *remove, alpm_list_t *upgrade);
+alpm_list_t *alpm_deptest(pmdb_t *db, alpm_list_t *targets);
+alpm_list_t *alpm_find_pkg_satisfiers(alpm_list_t *pkgs, const char *pkgname);
const char *alpm_miss_get_target(const pmdepmissing_t *miss);
pmdepend_t *alpm_miss_get_dep(pmdepmissing_t *miss);
+const char *alpm_miss_get_causingpkg(const pmdepmissing_t *miss);
+
+alpm_list_t *alpm_checkdbconflicts(pmdb_t *db_local);
const char *alpm_conflict_get_package1(pmconflict_t *conflict);
const char *alpm_conflict_get_package2(pmconflict_t *conflict);
@@ -439,12 +490,6 @@ enum _pmerrno_t {
PM_ERR_DB_REMOVE,
/* Servers */
PM_ERR_SERVER_BAD_URL,
- /* Configuration */
- PM_ERR_OPT_LOGFILE,
- PM_ERR_OPT_DBPATH,
- PM_ERR_OPT_LOCALDB,
- PM_ERR_OPT_SYNCDB,
- PM_ERR_OPT_USESYSLOG,
/* Transactions */
PM_ERR_TRANS_NOT_NULL,
PM_ERR_TRANS_NULL,
@@ -460,14 +505,12 @@ enum _pmerrno_t {
PM_ERR_PKG_INVALID,
PM_ERR_PKG_OPEN,
PM_ERR_PKG_LOAD,
- PM_ERR_PKG_INSTALLED,
PM_ERR_PKG_CANT_FRESH,
PM_ERR_PKG_CANT_REMOVE,
PM_ERR_PKG_INVALID_NAME,
- PM_ERR_PKG_CORRUPTED,
PM_ERR_PKG_REPO_NOT_FOUND,
/* Deltas */
- PM_ERR_DLT_CORRUPTED,
+ PM_ERR_DLT_INVALID,
PM_ERR_DLT_PATCHFAILED,
/* Groups */
PM_ERR_GRP_NOT_FOUND,
@@ -478,14 +521,14 @@ enum _pmerrno_t {
/* Misc */
PM_ERR_USER_ABORT,
PM_ERR_INTERNAL_ERROR,
- PM_ERR_LIBARCHIVE_ERROR,
PM_ERR_DB_SYNC,
PM_ERR_RETRIEVE,
PM_ERR_PKG_HOLD,
PM_ERR_INVALID_REGEX,
- /* Downloading */
- PM_ERR_CONNECT_FAILED,
- PM_ERR_FORK_FAILED
+ /* External library errors */
+ PM_ERR_LIBARCHIVE,
+ PM_ERR_LIBDOWNLOAD,
+ PM_ERR_EXTERNAL_DOWNLOAD
};
extern enum _pmerrno_t pm_errno;
diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c
index 57c8376a..87567402 100644
--- a/lib/libalpm/alpm_list.c
+++ b/lib/libalpm/alpm_list.c
@@ -1,7 +1,7 @@
/*
* alpm_list.c
*
- * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
+ * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,15 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "config.h"
-
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* libalpm */
#include "alpm_list.h"
-#include "util.h"
+
+/* check exported library symbols with: nm -C -D <lib> */
+#define SYMEXPORT __attribute__((visibility("default")))
+#define SYMHIDDEN __attribute__((visibility("internal")))
/**
* @addtogroup alpm_list List Functions
@@ -40,25 +41,6 @@
/* Allocation */
/**
- * @brief Allocate a new alpm_list_t.
- *
- * @return a new alpm_list_t item, or NULL on failure
- */
-alpm_list_t SYMEXPORT *alpm_list_new()
-{
- alpm_list_t *list = NULL;
-
- list = malloc(sizeof(alpm_list_t));
- if(list) {
- list->data = NULL;
- list->prev = list; /* maintain a back reference to the tail pointer */
- list->next = NULL;
- }
-
- return(list);
-}
-
-/**
* @brief Free a list, but not the contained data.
*
* @param list the list to free
@@ -107,30 +89,26 @@ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data)
{
alpm_list_t *ptr, *lp;
- ptr = list;
+ ptr = calloc(1, sizeof(alpm_list_t));
if(ptr == NULL) {
- ptr = alpm_list_new();
- if(ptr == NULL) {
- return(NULL);
- }
+ return(list);
}
- lp = alpm_list_last(ptr);
- if(lp == ptr && lp->data == NULL) {
- /* nada */
- } else {
- lp->next = alpm_list_new();
- if(lp->next == NULL) {
- return(NULL);
- }
- lp->next->prev = lp;
- lp = lp->next;
- list->prev = lp;
+ ptr->data = data;
+ ptr->next = NULL;
+
+ /* Special case: the input list is empty */
+ if(list == NULL) {
+ ptr->prev = ptr;
+ return(ptr);
}
- lp->data = data;
+ lp = alpm_list_last(list);
+ lp->next = ptr;
+ ptr->prev = lp;
+ list->prev = ptr;
- return(ptr);
+ return(list);
}
/**
@@ -144,12 +122,15 @@ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data)
*/
alpm_list_t SYMEXPORT *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn)
{
- if(!fn) {
- return alpm_list_add(list, data);
+ if(!fn || !list) {
+ return(alpm_list_add(list, data));
} else {
alpm_list_t *add = NULL, *prev = NULL, *next = list;
- add = alpm_list_new();
+ add = calloc(1, sizeof(alpm_list_t));
+ if(add == NULL) {
+ return(list);
+ }
add->data = data;
/* Find insertion point. */
@@ -159,26 +140,25 @@ alpm_list_t SYMEXPORT *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_
next = next->next;
}
- /* Insert node before insertion point. */
- add->prev = prev;
- add->next = next;
-
- if(next != NULL) {
- next->prev = add; /* Not at end. */
- }
-
- if(prev != NULL) {
- prev->next = add; /* In middle. */
- } else {
- list = add; /* At beginning, or new list */
- }
-
- if(next == NULL) {
- /* At end, adjust tail pointer on head node */
+ /* Insert the add node to the list */
+ if(prev == NULL) { /* special case: we insert add as the first element */
+ add->prev = list->prev; /* list != NULL */
+ add->next = list;
list->prev = add;
+ return(add);
+ } else if(next == NULL) { /* another special case: add last element */
+ add->prev = prev;
+ add->next = NULL;
+ prev->next = add;
+ list->prev = add;
+ return(list);
+ } else {
+ add->prev = prev;
+ add->next = next;
+ next->prev = add;
+ prev->next = add;
+ return(list);
}
-
- return(list);
}
}
@@ -198,10 +178,10 @@ alpm_list_t SYMEXPORT *alpm_list_join(alpm_list_t *first, alpm_list_t *second)
alpm_list_t *tmp;
if (first == NULL) {
- return second;
+ return(second);
}
if (second == NULL) {
- return first;
+ return(first);
}
/* tmp is the last element of the first list */
tmp = first->prev;
@@ -327,7 +307,7 @@ alpm_list_t SYMEXPORT *alpm_list_remove(alpm_list_t *haystack, const void *needl
continue;
}
tmp = i->next;
- if(fn(needle, i->data) == 0) {
+ if(fn(i->data, needle) == 0) {
/* we found a matching item */
if(i == haystack) {
/* Special case: removing the head node which has a back reference to
@@ -371,6 +351,22 @@ alpm_list_t SYMEXPORT *alpm_list_remove(alpm_list_t *haystack, const void *needl
}
/**
+ * @brief Remove a string from a list.
+ *
+ * @param haystack the list to remove the item from
+ * @param needle the data member of the item we're removing
+ * @param data output parameter containing data of the removed item
+ *
+ * @return the resultant list
+ */
+alpm_list_t SYMEXPORT *alpm_list_remove_str(alpm_list_t *haystack,
+ const char *needle, char **data)
+{
+ return(alpm_list_remove(haystack, (const void *)needle,
+ (alpm_list_fn_cmp)strcmp, (void **)data));
+}
+
+/**
* @brief Create a new list without any duplicates.
*
* This does NOT copy data members.
@@ -464,18 +460,22 @@ alpm_list_t SYMEXPORT *alpm_list_copy_data(const alpm_list_t *list,
alpm_list_t SYMEXPORT *alpm_list_reverse(alpm_list_t *list)
{
const alpm_list_t *lp;
- alpm_list_t *newlist = NULL;
+ alpm_list_t *newlist = NULL, *backup;
- lp = alpm_list_last(list);
- if(list) {
- /* break our reverse circular list */
- list->prev = NULL;
+ if(list == NULL) {
+ return(NULL);
}
+ lp = alpm_list_last(list);
+ /* break our reverse circular list */
+ backup = list->prev;
+ list->prev = NULL;
+
while(lp) {
newlist = alpm_list_add(newlist, lp->data);
lp = lp->prev;
}
+ list->prev = backup; /* restore tail pointer */
return(newlist);
}
@@ -490,14 +490,18 @@ alpm_list_t SYMEXPORT *alpm_list_reverse(alpm_list_t *list)
*/
inline alpm_list_t SYMEXPORT *alpm_list_first(const alpm_list_t *list)
{
- return((alpm_list_t*)list);
+ if(list) {
+ return((alpm_list_t*)list);
+ } else {
+ return(NULL);
+ }
}
/**
* @brief Return nth element from list (starting from 0).
*
* @param list the list
- * @param n the index of the item to find
+ * @param n the index of the item to find (n < alpm_list_count(list) IS needed)
*
* @return an alpm_list_t node for index `n`
*/
@@ -519,7 +523,11 @@ alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, int n)
*/
inline alpm_list_t SYMEXPORT *alpm_list_next(const alpm_list_t *node)
{
- return(node->next);
+ if(node) {
+ return(node->next);
+ } else {
+ return(NULL);
+ }
}
/**
@@ -594,7 +602,7 @@ void SYMEXPORT *alpm_list_find(const alpm_list_t *haystack, const void *needle,
}
/* trivial helper function for alpm_list_find_ptr */
-static int ptrcmp(const void *p, const void *q)
+static int ptr_cmp(const void *p, const void *q)
{
return(p != q);
}
@@ -611,7 +619,7 @@ static int ptrcmp(const void *p, const void *q)
*/
void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle)
{
- return(alpm_list_find(haystack, needle, ptrcmp));
+ return(alpm_list_find(haystack, needle, ptr_cmp));
}
/**
@@ -622,9 +630,11 @@ void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack, const void *need
*
* @return `needle` if found, NULL otherwise
*/
-char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack, const char *needle)
+char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack,
+ const char *needle)
{
- return((char *)alpm_list_find(haystack, (const void*)needle, (alpm_list_fn_cmp)strcmp));
+ return((char *)alpm_list_find(haystack, (const void*)needle,
+ (alpm_list_fn_cmp)strcmp));
}
/**
diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h
index ae373910..8dc8c5ff 100644
--- a/lib/libalpm/alpm_list.h
+++ b/lib/libalpm/alpm_list.h
@@ -19,6 +19,8 @@
#ifndef _ALPM_LIST_H
#define _ALPM_LIST_H
+#include <stdlib.h> /* size_t */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -45,7 +47,6 @@ typedef void (*alpm_list_fn_free)(void *); /* item deallocation callback */
typedef int (*alpm_list_fn_cmp)(const void *, const void *); /* item comparison callback */
/* allocation */
-alpm_list_t *alpm_list_new(void);
void alpm_list_free(alpm_list_t *list);
void alpm_list_free_inner(alpm_list_t *list, alpm_list_fn_free fn);
@@ -56,6 +57,7 @@ alpm_list_t *alpm_list_join(alpm_list_t *first, alpm_list_t *second);
alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn);
alpm_list_t *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn);
alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data);
+alpm_list_t *alpm_list_remove_str(alpm_list_t *haystack, const char *needle, char **data);
alpm_list_t *alpm_list_remove_dupes(const alpm_list_t *list);
alpm_list_t *alpm_list_strdup(const alpm_list_t *list);
alpm_list_t *alpm_list_copy(const alpm_list_t *list);
diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c
index 4cd0985e..2302374d 100644
--- a/lib/libalpm/be_files.c
+++ b/lib/libalpm/be_files.c
@@ -36,32 +36,171 @@
/* libalpm */
#include "db.h"
#include "alpm_list.h"
+#include "cache.h"
#include "log.h"
#include "util.h"
#include "alpm.h"
-#include "error.h"
#include "handle.h"
#include "package.h"
#include "delta.h"
#include "deps.h"
+#include "dload.h"
-/* This function is used to convert the downloaded db file to the proper backend
- * format
+/*
+ * Return the last update time as number of seconds from the epoch.
+ * Returns 0 if the value is unknown or can't be read.
*/
-int _alpm_db_install(pmdb_t *db, const char *dbfile)
+time_t getlastupdate(const pmdb_t *db)
{
+ FILE *fp;
+ char *file;
+ time_t ret = 0;
+
ALPM_LOG_FUNC;
- /* TODO we should not simply unpack the archive, but better parse it and
- * db_write each entry (see sync_load_dbarchive to get archive content) */
- _alpm_log(PM_LOG_DEBUG, "unpacking database '%s'\n", dbfile);
+ if(db == NULL) {
+ return(ret);
+ }
+
+ /* db->path + '.lastupdate' + NULL */
+ MALLOC(file, strlen(db->path) + 12, RET_ERR(PM_ERR_MEMORY, ret));
+ sprintf(file, "%s.lastupdate", db->path);
+
+ /* get the last update time, if it's there */
+ if((fp = fopen(file, "r")) == NULL) {
+ free(file);
+ return(ret);
+ } else {
+ char line[64];
+ if(fgets(line, sizeof(line), fp)) {
+ ret = atol(line);
+ }
+ }
+ fclose(fp);
+ free(file);
+ return(ret);
+}
+
+/*
+ * writes the dbpath/.lastupdate file with the value in time
+ */
+int setlastupdate(const pmdb_t *db, time_t time)
+{
+ FILE *fp;
+ char *file;
+ int ret = 0;
+
+ ALPM_LOG_FUNC;
- if(_alpm_unpack(dbfile, db->path, NULL)) {
- RET_ERR(PM_ERR_SYSTEM, -1);
+ if(db == NULL || time == 0) {
+ return(-1);
}
- return unlink(dbfile);
+ /* db->path + '.lastupdate' + NULL */
+ MALLOC(file, strlen(db->path) + 12, RET_ERR(PM_ERR_MEMORY, ret));
+ sprintf(file, "%s.lastupdate", db->path);
+
+ if((fp = fopen(file, "w")) == NULL) {
+ free(file);
+ return(-1);
+ }
+ if(fprintf(fp, "%ju", (uintmax_t)time) <= 0) {
+ ret = -1;
+ }
+ fclose(fp);
+ free(file);
+ return(ret);
+}
+
+/** Update a package database
+ * @param force if true, then forces the update, otherwise update only in case
+ * the database isn't up to date
+ * @param db pointer to the package database to update
+ * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
+ * to date
+ */
+int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
+{
+ alpm_list_t *lp;
+ char path[PATH_MAX];
+ time_t newmtime = 0, lastupdate = 0;
+ const char *dbpath;
+ int ret;
+
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
+ ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ /* Verify we are in a transaction. This is done _mainly_ because we need a DB
+ * lock - if we update without a db lock, we may kludge some other pacman
+ * process that _has_ a lock.
+ */
+ ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
+ ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
+ ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1));
+
+ if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
+ RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+ }
+
+ if(!force) {
+ /* get the lastupdate time */
+ lastupdate = getlastupdate(db);
+ if(lastupdate == 0) {
+ _alpm_log(PM_LOG_DEBUG, "failed to get lastupdate time for %s\n",
+ db->treename);
+ }
+ }
+
+ snprintf(path, PATH_MAX, "%s" DBEXT, db->treename);
+ dbpath = alpm_option_get_dbpath();
+
+ ret = _alpm_download_single_file(path, db->servers, dbpath,
+ lastupdate, &newmtime);
+
+ if(ret == 1) {
+ /* mtimes match, do nothing */
+ pm_errno = 0;
+ return(1);
+ } else if(ret == -1) {
+ /* pm_errno was set by the download code */
+ _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
+ return(-1);
+ } else {
+ /* form the path to the db location */
+ snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename);
+
+ /* remove the old dir */
+ _alpm_log(PM_LOG_DEBUG, "flushing database %s\n", db->path);
+ for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
+ pmpkg_t *pkg = lp->data;
+ if(pkg && _alpm_db_remove(db, pkg) == -1) {
+ _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s%s\n"),
+ db->treename, pkg->name);
+ RET_ERR(PM_ERR_DB_REMOVE, -1);
+ }
+ }
+
+ /* Cache needs to be rebuilt */
+ _alpm_db_free_pkgcache(db);
+
+ /* uncompress the sync database */
+ if(_alpm_unpack(path, db->path, NULL)) {
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
+ unlink(path);
+
+ /* if we have a new mtime, set the DB last update value */
+ if(newmtime) {
+ _alpm_log(PM_LOG_DEBUG, "sync: new mtime for %s: %ju\n",
+ db->treename, (uintmax_t)newmtime);
+ setlastupdate(db, newmtime);
+ }
+ }
+
+ return(0);
}
int _alpm_db_open(pmdb_t *db)
@@ -95,18 +234,7 @@ void _alpm_db_close(pmdb_t *db)
}
}
-void _alpm_db_rewind(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL || db->handle == NULL) {
- return;
- }
-
- rewinddir(db->handle);
-}
-
-static int _alpm_db_splitname(const char *target, char *name, char *version)
+static int splitname(const char *target, pmpkg_t *pkg)
{
/* the format of a db entry is as follows:
* package-version-rel/
@@ -115,10 +243,10 @@ static int _alpm_db_splitname(const char *target, char *name, char *version)
*/
char *tmp, *p, *q;
- if(target == NULL) {
+ if(target == NULL || pkg == NULL) {
return(-1);
}
- tmp = strdup(target);
+ STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1));
p = tmp + strlen(tmp);
/* do the magic parsing- find the beginning of the version string
@@ -130,119 +258,82 @@ static int _alpm_db_splitname(const char *target, char *name, char *version)
}
/* copy into fields and return */
- if(version) {
- strncpy(version, p+1, PKG_VERSION_LEN);
+ if(pkg->version) {
+ FREE(pkg->version);
}
+ STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1));
/* insert a terminator at the end of the name (on hyphen)- then copy it */
*p = '\0';
- if(name) {
- strncpy(name, tmp, PKG_NAME_LEN);
+ if(pkg->name) {
+ FREE(pkg->name);
}
+ STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1));
free(tmp);
return(0);
}
-pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target)
+int _alpm_db_populate(pmdb_t *db)
{
+ int count = 0;
struct dirent *ent = NULL;
struct stat sbuf;
char path[PATH_MAX];
- char name[PKG_FULLNAME_LEN];
- char *ptr = NULL;
- int found = 0;
- pmpkg_t *pkg = NULL;
ALPM_LOG_FUNC;
- if(db == NULL) {
- RET_ERR(PM_ERR_DB_NULL, NULL);
- }
+ ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
- /* We loop here until we read a valid package. When an iteration of this loop
- * fails, it means alpm_db_read failed to read a valid package, so we'll read
- * the next so as not to abort whole-db operations early
- */
- while(!pkg) {
- if(target != NULL) {
- /* search for a specific package (by name only) */
- rewinddir(db->handle);
- while(!found && (ent = readdir(db->handle)) != NULL) {
- if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
- continue;
- }
- /* stat the entry, make sure it's a directory */
- snprintf(path, PATH_MAX, "%s/%s", db->path, ent->d_name);
- if(stat(path, &sbuf) || !S_ISDIR(sbuf.st_mode)) {
- continue;
- }
- strncpy(name, ent->d_name, PKG_FULLNAME_LEN);
- /* truncate the string at the second-to-last hyphen, */
- /* which will give us the package name */
- if((ptr = rindex(name, '-'))) {
- *ptr = '\0';
- }
- if((ptr = rindex(name, '-'))) {
- *ptr = '\0';
- }
- if(!strcmp(name, target)) {
- found = 1;
- }
- }
- if(!found) {
- return(NULL);
- }
- } else { /* target == NULL, full scan */
- int isdir = 0;
- while(!isdir) {
- ent = readdir(db->handle);
- if(ent == NULL) {
- return(NULL);
- }
- if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
- isdir = 0;
- continue;
- }
- /* stat the entry, make sure it's a directory */
- snprintf(path, PATH_MAX, "%s/%s", db->path, ent->d_name);
- if(!stat(path, &sbuf) && S_ISDIR(sbuf.st_mode)) {
- isdir = 1;
- }
- }
+ rewinddir(db->handle);
+ while((ent = readdir(db->handle)) != NULL) {
+ const char *name = ent->d_name;
+ pmpkg_t *pkg;
+
+ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ continue;
+ }
+ /* stat the entry, make sure it's a directory */
+ snprintf(path, PATH_MAX, "%s/%s", db->path, name);
+ if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
+ continue;
}
- pkg = _alpm_pkg_new(NULL, NULL);
+ pkg = _alpm_pkg_new();
if(pkg == NULL) {
- _alpm_log(PM_LOG_DEBUG, "db scan could not find package: %s\n", target);
- return(NULL);
+ return(-1);
}
/* split the db entry name */
- if(_alpm_db_splitname(ent->d_name, pkg->name, pkg->version) != 0) {
+ if(splitname(name, pkg) != 0) {
_alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
- ent->d_name);
- alpm_pkg_free(pkg);
- pkg = NULL;
+ name);
+ _alpm_pkg_free(pkg);
continue;
}
/* explicitly read with only 'BASE' data, accessors will handle the rest */
if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) {
- /* TODO removed corrupt entry from the FS here */
+ _alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);
_alpm_pkg_free(pkg);
- } else {
- pkg->origin = PKG_FROM_CACHE;
- pkg->origin_data.db = db;
+ continue;
}
+ pkg->origin = PKG_FROM_CACHE;
+ pkg->origin_data.db = db;
+ /* add to the collection */
+ _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
+ pkg->name, db->treename);
+ db->pkgcache = alpm_list_add(db->pkgcache, pkg);
+ count++;
}
- return(pkg);
+ db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp);
+ return(count);
}
int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
{
FILE *fp = NULL;
struct stat buf;
- char path[PATH_MAX+1];
+ char path[PATH_MAX];
char line[513];
ALPM_LOG_FUNC;
@@ -251,7 +342,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
RET_ERR(PM_ERR_DB_NULL, -1);
}
- if(info == NULL || info->name[0] == 0 || info->version[0] == 0) {
+ if(info == NULL || info->name == NULL || info->version == NULL) {
_alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n");
return(-1);
}
@@ -296,120 +387,131 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
break;
}
_alpm_strtrim(line);
- if(!strcmp(line, "%FILENAME%")) {
- if(fgets(info->filename, sizeof(info->filename), fp) == NULL) {
+ if(strcmp(line, "%NAME%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
+ goto error;
+ }
+ if(strcmp(_alpm_strtrim(line), info->name) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
+ "mismatch on package %s\n"), db->treename, info->name);
+ }
+ } else if(strcmp(line, "%VERSION%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(info->filename);
- } else if(!strcmp(line, "%DESC%")) {
- if(fgets(info->desc, sizeof(info->desc), fp) == NULL) {
+ if(strcmp(_alpm_strtrim(line), info->version) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
+ "mismatch on package %s\n"), db->treename, info->name);
+ }
+ } else if(strcmp(line, "%FILENAME%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(info->desc);
- } else if(!strcmp(line, "%GROUPS%")) {
+ STRDUP(info->filename, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%DESC%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
+ goto error;
+ }
+ STRDUP(info->desc, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%GROUPS%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->groups = alpm_list_add(info->groups, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->groups = alpm_list_add(info->groups, linedup);
}
- } else if(!strcmp(line, "%URL%")) {
- if(fgets(info->url, sizeof(info->url), fp) == NULL) {
+ } else if(strcmp(line, "%URL%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(info->url);
- } else if(!strcmp(line, "%LICENSE%")) {
+ STRDUP(info->url, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%LICENSE%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->licenses = alpm_list_add(info->licenses, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->licenses = alpm_list_add(info->licenses, linedup);
}
- } else if(!strcmp(line, "%ARCH%")) {
- if(fgets(info->arch, sizeof(info->arch), fp) == NULL) {
+ } else if(strcmp(line, "%ARCH%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(info->arch);
- } else if(!strcmp(line, "%BUILDDATE%")) {
- char tmp[32];
- if(fgets(tmp, sizeof(tmp), fp) == NULL) {
+ STRDUP(info->arch, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%BUILDDATE%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(tmp);
+ _alpm_strtrim(line);
- char first = tolower(tmp[0]);
+ char first = tolower(line[0]);
if(first > 'a' && first < 'z') {
struct tm tmp_tm = {0}; //initialize to null incase of failure
setlocale(LC_TIME, "C");
- strptime(tmp, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+ strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
info->builddate = mktime(&tmp_tm);
setlocale(LC_TIME, "");
} else {
- info->builddate = atol(tmp);
+ info->builddate = atol(line);
}
- } else if(!strcmp(line, "%INSTALLDATE%")) {
- char tmp[32];
- if(fgets(tmp, sizeof(tmp), fp) == NULL) {
+ } else if(strcmp(line, "%INSTALLDATE%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(tmp);
+ _alpm_strtrim(line);
- char first = tolower(tmp[0]);
+ char first = tolower(line[0]);
if(first > 'a' && first < 'z') {
struct tm tmp_tm = {0}; //initialize to null incase of failure
setlocale(LC_TIME, "C");
- strptime(tmp, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+ strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
info->installdate = mktime(&tmp_tm);
setlocale(LC_TIME, "");
} else {
- info->installdate = atol(tmp);
+ info->installdate = atol(line);
}
- } else if(!strcmp(line, "%PACKAGER%")) {
- if(fgets(info->packager, sizeof(info->packager), fp) == NULL) {
+ } else if(strcmp(line, "%PACKAGER%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(info->packager);
- } else if(!strcmp(line, "%REASON%")) {
- char tmp[32];
- if(fgets(tmp, sizeof(tmp), fp) == NULL) {
+ STRDUP(info->packager, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%REASON%") == 0) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(tmp);
- info->reason = atol(tmp);
- } else if(!strcmp(line, "%SIZE%") || !strcmp(line, "%CSIZE%")) {
+ info->reason = atol(_alpm_strtrim(line));
+ } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) {
/* NOTE: the CSIZE and SIZE fields both share the "size" field
* in the pkginfo_t struct. This can be done b/c CSIZE
* is currently only used in sync databases, and SIZE is
* only used in local databases.
*/
- char tmp[32];
- if(fgets(tmp, sizeof(tmp), fp) == NULL) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(tmp);
- info->size = atol(tmp);
+ info->size = atol(_alpm_strtrim(line));
/* also store this value to isize if isize is unset */
if(info->isize == 0) {
- info->isize = atol(tmp);
+ info->isize = info->size;
}
- } else if(!strcmp(line, "%ISIZE%")) {
+ } else if(strcmp(line, "%ISIZE%") == 0) {
/* ISIZE (installed size) tag only appears in sync repositories,
* not the local one. */
- char tmp[32];
- if(fgets(tmp, sizeof(tmp), fp) == NULL) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- _alpm_strtrim(tmp);
- info->isize = atol(tmp);
- } else if(!strcmp(line, "%MD5SUM%")) {
+ info->isize = atol(_alpm_strtrim(line));
+ } else if(strcmp(line, "%MD5SUM%") == 0) {
/* MD5SUM tag only appears in sync repositories,
* not the local one. */
- if(fgets(info->md5sum, sizeof(info->md5sum), fp) == NULL) {
+ if(fgets(line, 512, fp) == NULL) {
goto error;
}
- } else if(!strcmp(line, "%REPLACES%")) {
- /* the REPLACES tag is special -- it only appears in sync repositories,
- * not the local one. */
+ STRDUP(info->md5sum, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%REPLACES%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->replaces = alpm_list_add(info->replaces, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->replaces = alpm_list_add(info->replaces, linedup);
}
- } else if(!strcmp(line, "%FORCE%")) {
- /* FORCE tag only appears in sync repositories,
- * not the local one. */
+ } else if(strcmp(line, "%FORCE%") == 0) {
info->force = 1;
}
}
@@ -426,13 +528,17 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
}
while(fgets(line, 256, fp)) {
_alpm_strtrim(line);
- if(!strcmp(line, "%FILES%")) {
+ if(strcmp(line, "%FILES%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->files = alpm_list_add(info->files, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->files = alpm_list_add(info->files, linedup);
}
- } else if(!strcmp(line, "%BACKUP%")) {
+ } else if(strcmp(line, "%BACKUP%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->backup = alpm_list_add(info->backup, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->backup = alpm_list_add(info->backup, linedup);
}
}
}
@@ -450,37 +556,30 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
while(!feof(fp)) {
fgets(line, 255, fp);
_alpm_strtrim(line);
- if(!strcmp(line, "%DEPENDS%")) {
+ if(strcmp(line, "%DEPENDS%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- pmdepend_t *dep = alpm_splitdep(line);
+ pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line));
info->depends = alpm_list_add(info->depends, dep);
}
- } else if(!strcmp(line, "%OPTDEPENDS%")) {
+ } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->optdepends = alpm_list_add(info->optdepends, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->optdepends = alpm_list_add(info->optdepends, linedup);
}
- } else if(!strcmp(line, "%CONFLICTS%")) {
+ } else if(strcmp(line, "%CONFLICTS%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->conflicts = alpm_list_add(info->conflicts, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->conflicts = alpm_list_add(info->conflicts, linedup);
}
- } else if(!strcmp(line, "%PROVIDES%")) {
+ } else if(strcmp(line, "%PROVIDES%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->provides = alpm_list_add(info->provides, strdup(line));
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->provides = alpm_list_add(info->provides, linedup);
}
}
- /* TODO: we were going to move these things here, but it should wait.
- * A better change would be to figure out how to restructure the DB. */
- /* else if(!strcmp(line, "%REPLACES%")) {
- * the REPLACES tag is special -- it only appears in sync repositories,
- * not the local one. *
- while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
- info->replaces = alpm_list_add(info->replaces, strdup(line));
- }
- } else if(!strcmp(line, "%FORCE%")) {
- * FORCE tag only appears in sync repositories,
- * not the local one. *
- info->force = 1;
- } */
}
fclose(fp);
fp = NULL;
@@ -488,12 +587,13 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
/* DELTAS */
if(inforeq & INFRQ_DELTAS) {
- snprintf(path, PATH_MAX, "%s/%s-%s/deltas", db->path, info->name, info->version);
+ snprintf(path, PATH_MAX, "%s/%s-%s/deltas", db->path,
+ info->name, info->version);
if((fp = fopen(path, "r"))) {
while(!feof(fp)) {
fgets(line, 255, fp);
_alpm_strtrim(line);
- if(!strcmp(line, "%DELTAS%")) {
+ if(strcmp(line, "%DELTAS%") == 0) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->deltas = alpm_list_add(info->deltas, _alpm_delta_parse(line));
}
@@ -561,7 +661,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
}
fprintf(fp, "%%NAME%%\n%s\n\n"
"%%VERSION%%\n%s\n\n", info->name, info->version);
- if(info->desc[0]) {
+ if(info->desc) {
fprintf(fp, "%%DESC%%\n"
"%s\n\n", info->desc);
}
@@ -572,8 +672,18 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
}
fprintf(fp, "\n");
}
+ if(info->replaces) {
+ fputs("%REPLACES%\n", fp);
+ for(lp = info->replaces; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->force) {
+ fprintf(fp, "%%FORCE%%\n\n");
+ }
if(local) {
- if(info->url[0]) {
+ if(info->url) {
fprintf(fp, "%%URL%%\n"
"%s\n\n", info->url);
}
@@ -584,7 +694,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
}
fprintf(fp, "\n");
}
- if(info->arch[0]) {
+ if(info->arch) {
fprintf(fp, "%%ARCH%%\n"
"%s\n\n", info->arch);
}
@@ -596,7 +706,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
fprintf(fp, "%%INSTALLDATE%%\n"
"%ju\n\n", (uintmax_t)info->installdate);
}
- if(info->packager[0]) {
+ if(info->packager) {
fprintf(fp, "%%PACKAGER%%\n"
"%s\n\n", info->packager);
}
@@ -695,19 +805,6 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
}
fprintf(fp, "\n");
}
- if(!local) {
- if(info->replaces) {
- fputs("%REPLACES%\n", fp);
- for(lp = info->replaces; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->force) {
- fprintf(fp, "%%FORCE%%\n"
- "\n");
- }
- }
fclose(fp);
fp = NULL;
}
@@ -743,63 +840,4 @@ int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
return(0);
}
-/*
- * Return the last update time as number of seconds from the epoch.
- * Returns 0 if the value is unknown or can't be read.
- */
-time_t _alpm_db_getlastupdate(const pmdb_t *db)
-{
- FILE *fp;
- char file[PATH_MAX];
- time_t ret = 0;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(ret);
- }
-
- snprintf(file, PATH_MAX, "%s.lastupdate", db->path);
-
- /* get the last update time, if it's there */
- if((fp = fopen(file, "r")) == NULL) {
- return(ret);
- } else {
- char line[64];
- if(fgets(line, sizeof(line), fp)) {
- ret = atol(line);
- }
- }
- fclose(fp);
- return(ret);
-}
-
-/*
- * writes the dbpath/.lastupdate file with the value in time
- */
-int _alpm_db_setlastupdate(const pmdb_t *db, time_t time)
-{
- FILE *fp;
- char file[PATH_MAX];
- int ret = 0;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || time == 0) {
- return(-1);
- }
-
- snprintf(file, PATH_MAX, "%s.lastupdate", db->path);
-
- if((fp = fopen(file, "w")) == NULL) {
- return(-1);
- }
- if(fprintf(fp, "%ju", (uintmax_t)time) <= 0) {
- ret = -1;
- }
- fclose(fp);
-
- return(ret);
-}
-
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
new file mode 100644
index 00000000..85112fd4
--- /dev/null
+++ b/lib/libalpm/be_package.c
@@ -0,0 +1,285 @@
+/*
+ * be_package.c
+ *
+ * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <locale.h> /* setlocale */
+
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
+/* libalpm */
+#include "alpm_list.h"
+#include "util.h"
+#include "log.h"
+#include "package.h"
+#include "deps.h" /* _alpm_splitdep */
+
+/**
+ * Parses the package description file for a package into a pmpkg_t struct.
+ * @param archive the archive to read from, pointed at the .PKGINFO entry
+ * @param newpkg an empty pmpkg_t struct to fill with package info
+ *
+ * @return 0 on success, 1 on error
+ */
+static int parse_descfile(struct archive *a, pmpkg_t *newpkg)
+{
+ char line[PATH_MAX];
+ char *ptr = NULL;
+ char *key = NULL;
+ int linenum = 0;
+
+ ALPM_LOG_FUNC;
+
+ /* loop until we reach EOF (where archive_fgets will return NULL) */
+ while(_alpm_archive_fgets(line, PATH_MAX, a) != NULL) {
+ linenum++;
+ _alpm_strtrim(line);
+ if(strlen(line) == 0 || line[0] == '#') {
+ continue;
+ }
+ ptr = line;
+ key = strsep(&ptr, "=");
+ if(key == NULL || ptr == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n",
+ newpkg->name ? newpkg->name : "error", linenum);
+ } else {
+ key = _alpm_strtrim(key);
+ ptr = _alpm_strtrim(ptr);
+ if(!strcmp(key, "pkgname")) {
+ STRDUP(newpkg->name, ptr, RET_ERR(PM_ERR_MEMORY, -1));
+ } else if(!strcmp(key, "pkgver")) {
+ STRDUP(newpkg->version, ptr, RET_ERR(PM_ERR_MEMORY, -1));
+ } else if(!strcmp(key, "pkgdesc")) {
+ STRDUP(newpkg->desc, ptr, RET_ERR(PM_ERR_MEMORY, -1));
+ } else if(!strcmp(key, "group")) {
+ newpkg->groups = alpm_list_add(newpkg->groups, strdup(ptr));
+ } else if(!strcmp(key, "url")) {
+ STRDUP(newpkg->url, ptr, RET_ERR(PM_ERR_MEMORY, -1));
+ } else if(!strcmp(key, "license")) {
+ newpkg->licenses = alpm_list_add(newpkg->licenses, strdup(ptr));
+ } else if(!strcmp(key, "builddate")) {
+ char first = tolower(ptr[0]);
+ if(first > 'a' && first < 'z') {
+ struct tm tmp_tm = {0}; //initialize to null in case of failure
+ setlocale(LC_TIME, "C");
+ strptime(ptr, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+ newpkg->builddate = mktime(&tmp_tm);
+ setlocale(LC_TIME, "");
+ } else {
+ newpkg->builddate = atol(ptr);
+ }
+ } else if(!strcmp(key, "packager")) {
+ STRDUP(newpkg->packager, ptr, RET_ERR(PM_ERR_MEMORY, -1));
+ } else if(!strcmp(key, "arch")) {
+ STRDUP(newpkg->arch, ptr, RET_ERR(PM_ERR_MEMORY, -1));
+ } else if(!strcmp(key, "size")) {
+ /* size in the raw package is uncompressed (installed) size */
+ newpkg->isize = atol(ptr);
+ } else if(!strcmp(key, "depend")) {
+ pmdepend_t *dep = _alpm_splitdep(ptr);
+ newpkg->depends = alpm_list_add(newpkg->depends, dep);
+ } else if(!strcmp(key, "optdepend")) {
+ newpkg->optdepends = alpm_list_add(newpkg->optdepends, strdup(ptr));
+ } else if(!strcmp(key, "conflict")) {
+ newpkg->conflicts = alpm_list_add(newpkg->conflicts, strdup(ptr));
+ } else if(!strcmp(key, "replaces")) {
+ newpkg->replaces = alpm_list_add(newpkg->replaces, strdup(ptr));
+ } else if(!strcmp(key, "provides")) {
+ newpkg->provides = alpm_list_add(newpkg->provides, strdup(ptr));
+ } else if(!strcmp(key, "backup")) {
+ newpkg->backup = alpm_list_add(newpkg->backup, strdup(ptr));
+ } else {
+ _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n",
+ newpkg->name ? newpkg->name : "error", linenum);
+ }
+ }
+ line[0] = '\0';
+ }
+
+ return(0);
+}
+
+/**
+ * Load a package and create the corresponding pmpkg_t struct.
+ * @param pkgfile path to the package file
+ * @param full whether to stop the load after metadata is read or continue
+ * through the full archive
+ * @return An information filled pmpkg_t struct
+ */
+static pmpkg_t *pkg_load(const char *pkgfile, unsigned short full)
+{
+ int ret = ARCHIVE_OK;
+ int config = 0;
+ struct archive *archive;
+ struct archive_entry *entry;
+ pmpkg_t *newpkg = NULL;
+ struct stat st;
+
+ ALPM_LOG_FUNC;
+
+ if(pkgfile == NULL || strlen(pkgfile) == 0) {
+ RET_ERR(PM_ERR_WRONG_ARGS, NULL);
+ }
+
+ if((archive = archive_read_new()) == NULL) {
+ RET_ERR(PM_ERR_LIBARCHIVE, NULL);
+ }
+
+ archive_read_support_compression_all(archive);
+ archive_read_support_format_all(archive);
+
+ if (archive_read_open_filename(archive, pkgfile,
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ RET_ERR(PM_ERR_PKG_OPEN, NULL);
+ }
+
+ newpkg = _alpm_pkg_new();
+ if(newpkg == NULL) {
+ archive_read_finish(archive);
+ RET_ERR(PM_ERR_MEMORY, NULL);
+ }
+
+ if(stat(pkgfile, &st) == 0) {
+ newpkg->size = st.st_size;
+ }
+
+ /* If full is false, only read through the archive until we find our needed
+ * metadata. If it is true, read through the entire archive, which serves
+ * as a verfication of integrity and allows us to create the filelist. */
+ while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
+ const char *entry_name = archive_entry_pathname(entry);
+
+ if(strcmp(entry_name, ".PKGINFO") == 0) {
+ /* parse the info file */
+ if(parse_descfile(archive, newpkg) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not parse package description file in %s\n"),
+ pkgfile);
+ goto pkg_invalid;
+ }
+ if(newpkg->name == NULL || strlen(newpkg->name) == 0) {
+ _alpm_log(PM_LOG_ERROR, _("missing package name in %s\n"), pkgfile);
+ goto pkg_invalid;
+ }
+ if(newpkg->version == NULL || strlen(newpkg->version) == 0) {
+ _alpm_log(PM_LOG_ERROR, _("missing package version in %s\n"), pkgfile);
+ goto pkg_invalid;
+ }
+ config = 1;
+ continue;
+ } else if(strcmp(entry_name, ".INSTALL") == 0) {
+ newpkg->scriptlet = 1;
+ } else if(*entry_name == '.') {
+ /* for now, ignore all files starting with '.' that haven't
+ * already been handled (for future possibilities) */
+ } else {
+ /* Keep track of all files for filelist generation */
+ newpkg->files = alpm_list_add(newpkg->files, strdup(entry_name));
+ }
+
+ if(archive_read_data_skip(archive)) {
+ _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"),
+ pkgfile, archive_error_string(archive));
+ pm_errno = PM_ERR_LIBARCHIVE;
+ goto error;
+ }
+
+ /* if we are not doing a full read, see if we have all we need */
+ if(!full && config) {
+ break;
+ }
+ }
+
+ if(ret != ARCHIVE_EOF && ret != ARCHIVE_OK) { /* An error occured */
+ _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"),
+ pkgfile, archive_error_string(archive));
+ pm_errno = PM_ERR_LIBARCHIVE;
+ goto error;
+ }
+
+ if(!config) {
+ _alpm_log(PM_LOG_ERROR, _("missing package metadata in %s\n"), pkgfile);
+ goto pkg_invalid;
+ }
+
+ archive_read_finish(archive);
+
+ /* internal fields for package struct */
+ newpkg->origin = PKG_FROM_FILE;
+ newpkg->origin_data.file = strdup(pkgfile);
+
+ if(full) {
+ /* "checking for conflicts" requires a sorted list, ensure that here */
+ _alpm_log(PM_LOG_DEBUG, "sorting package filelist for %s\n", pkgfile);
+ newpkg->files = alpm_list_msort(newpkg->files, alpm_list_count(newpkg->files),
+ _alpm_str_cmp);
+ newpkg->infolevel = INFRQ_ALL;
+ } else {
+ /* get rid of any partial filelist we may have collected, it is invalid */
+ FREELIST(newpkg->files);
+ newpkg->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS;
+ }
+
+ return(newpkg);
+
+pkg_invalid:
+ pm_errno = PM_ERR_PKG_INVALID;
+error:
+ _alpm_pkg_free(newpkg);
+ archive_read_finish(archive);
+
+ return(NULL);
+}
+
+/** Create a package from a file.
+ * If full is false, the archive is read only until all necessary
+ * metadata is found. If it is true, the entire archive is read, which
+ * serves as a verfication of integrity and the filelist can be created.
+ * @param filename location of the package tarball
+ * @param full whether to stop the load after metadata is read or continue
+ * through the full archive
+ * @param pkg address of the package pointer
+ * @return 0 on success, -1 on error (pm_errno is set accordingly)
+ */
+int SYMEXPORT alpm_pkg_load(const char *filename, unsigned short full,
+ pmpkg_t **pkg)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(filename != NULL && strlen(filename) != 0,
+ RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+
+ *pkg = pkg_load(filename, full);
+ if(*pkg == NULL) {
+ /* pm_errno is set by pkg_load */
+ return(-1);
+ }
+
+ return(0);
+}
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/cache.c b/lib/libalpm/cache.c
index 0ad923a5..b140476c 100644
--- a/lib/libalpm/cache.c
+++ b/lib/libalpm/cache.c
@@ -31,7 +31,6 @@
#include "log.h"
#include "alpm.h"
#include "util.h"
-#include "error.h"
#include "package.h"
#include "group.h"
#include "db.h"
@@ -41,32 +40,21 @@
*/
int _alpm_db_load_pkgcache(pmdb_t *db)
{
- pmpkg_t *info;
- int count = 0;
-
ALPM_LOG_FUNC;
if(db == NULL) {
return(-1);
}
-
_alpm_db_free_pkgcache(db);
_alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n",
- db->treename);
-
- _alpm_db_rewind(db);
- while((info = _alpm_db_scan(db, NULL)) != NULL) {
- _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
- alpm_pkg_get_name(info), db->treename);
- info->origin = PKG_FROM_CACHE;
- info->origin_data.db = db;
- /* add to the collection */
- db->pkgcache = alpm_list_add(db->pkgcache, info);
- count++;
+ db->treename);
+ if(_alpm_db_populate(db) == -1) {
+ _alpm_log(PM_LOG_DEBUG,
+ "failed to load package cache for repository '%s'\n", db->treename);
+ return(-1);
}
- db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp);
return(0);
}
@@ -81,10 +69,7 @@ void _alpm_db_free_pkgcache(pmdb_t *db)
_alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n",
db->treename);
- alpm_list_t *tmp;
- for(tmp = db->pkgcache; tmp; tmp = alpm_list_next(tmp)) {
- _alpm_pkg_free(tmp->data);
- }
+ alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free);
alpm_list_free(db->pkgcache);
db->pkgcache = NULL;
@@ -115,21 +100,15 @@ alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db)
int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)
{
- pmpkg_t *newpkg;
-
ALPM_LOG_FUNC;
if(db == NULL || pkg == NULL) {
return(-1);
}
- newpkg = _alpm_pkg_dup(pkg);
- if(newpkg == NULL) {
- return(-1);
- }
_alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
- alpm_pkg_get_name(newpkg), db->treename);
- db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp);
+ alpm_pkg_get_name(pkg), db->treename);
+ db->pkgcache = alpm_list_add_sorted(db->pkgcache, pkg, _alpm_pkg_cmp);
_alpm_db_free_grpcache(db);
@@ -181,7 +160,7 @@ pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target)
return(NULL);
}
- return(_alpm_pkg_find(target, pkgcache));
+ return(_alpm_pkg_find(pkgcache, target));
}
/* Returns a new group cache from db.
@@ -208,33 +187,29 @@ int _alpm_db_load_grpcache(pmdb_t *db)
pmpkg_t *pkg = lp->data;
for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
- if(!alpm_list_find_str(db->grpcache, i->data)) {
- pmgrp_t *grp = _alpm_grp_new();
-
- strncpy(grp->name, i->data, GRP_NAME_LEN);
- grp->name[GRP_NAME_LEN-1] = '\0';
- grp->packages = alpm_list_add_sorted(grp->packages,
- /* gross signature forces us to
- * discard const */
- (void*)alpm_pkg_get_name(pkg),
- _alpm_str_cmp);
- db->grpcache = alpm_list_add_sorted(db->grpcache, grp, _alpm_grp_cmp);
- } else {
- alpm_list_t *j;
-
- for(j = db->grpcache; j; j = j->next) {
- pmgrp_t *grp = j->data;
-
- if(strcmp(grp->name, i->data) == 0) {
- const char *pkgname = alpm_pkg_get_name(pkg);
- if(!alpm_list_find_str(grp->packages, pkgname)) {
- grp->packages = alpm_list_add_sorted(grp->packages,
- (void*)pkgname,
- _alpm_str_cmp);
- }
- }
+ const char *grpname = i->data;
+ alpm_list_t *j;
+ pmgrp_t *grp = NULL;
+ int found = 0;
+
+ /* first look through the group cache for a group with this name */
+ for(j = db->grpcache; j; j = j->next) {
+ grp = j->data;
+
+ if(strcmp(grp->name, grpname) == 0
+ && !alpm_list_find_ptr(grp->packages, pkg)) {
+ grp->packages = alpm_list_add(grp->packages, pkg);
+ found = 1;
+ break;
}
}
+ if(found) {
+ continue;
+ }
+ /* we didn't find the group, so create a new one with this name */
+ grp = _alpm_grp_new(grpname);
+ grp->packages = alpm_list_add(grp->packages, pkg);
+ db->grpcache = alpm_list_add(db->grpcache, grp);
}
}
@@ -252,10 +227,6 @@ void _alpm_db_free_grpcache(pmdb_t *db)
}
for(lg = db->grpcache; lg; lg = lg->next) {
- pmgrp_t *grp = lg->data;
-
- alpm_list_free(grp->packages);
- grp->packages = NULL;
_alpm_grp_free(lg->data);
lg->data = NULL;
}
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index 3442902c..a8bcdd59 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -36,7 +36,6 @@
#include "handle.h"
#include "trans.h"
#include "util.h"
-#include "error.h"
#include "log.h"
#include "cache.h"
#include "deps.h"
@@ -49,12 +48,30 @@ pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2)
MALLOC(conflict, sizeof(pmconflict_t), RET_ERR(PM_ERR_MEMORY, NULL));
- strncpy(conflict->package1, package1, PKG_NAME_LEN);
- strncpy(conflict->package2, package2, PKG_NAME_LEN);
+ STRDUP(conflict->package1, package1, RET_ERR(PM_ERR_MEMORY, NULL));
+ STRDUP(conflict->package2, package2, RET_ERR(PM_ERR_MEMORY, NULL));
return(conflict);
}
+void _alpm_conflict_free(pmconflict_t *conflict)
+{
+ FREE(conflict->package2);
+ FREE(conflict->package1);
+ FREE(conflict);
+}
+
+pmconflict_t *_alpm_conflict_dup(const pmconflict_t *conflict)
+{
+ pmconflict_t *newconflict;
+ CALLOC(newconflict, 1, sizeof(pmconflict_t), RET_ERR(PM_ERR_MEMORY, NULL));
+
+ STRDUP(newconflict->package1, conflict->package1, RET_ERR(PM_ERR_MEMORY, NULL));
+ STRDUP(newconflict->package2, conflict->package2, RET_ERR(PM_ERR_MEMORY, NULL));
+
+ return(newconflict);
+}
+
int _alpm_conflict_isin(pmconflict_t *needle, alpm_list_t *haystack)
{
alpm_list_t *i;
@@ -86,7 +103,7 @@ static int does_conflict(pmpkg_t *pkg1, const char *conflict, pmpkg_t *pkg2)
{
const char *pkg1name = alpm_pkg_get_name(pkg1);
const char *pkg2name = alpm_pkg_get_name(pkg2);
- pmdepend_t *conf = alpm_splitdep(conflict);
+ pmdepend_t *conf = _alpm_splitdep(conflict);
int match = 0;
match = alpm_depcmp(pkg2, conf);
@@ -94,7 +111,7 @@ static int does_conflict(pmpkg_t *pkg1, const char *conflict, pmpkg_t *pkg2)
_alpm_log(PM_LOG_DEBUG, "package %s conflicts with %s (by %s)\n",
pkg1name, pkg2name, conflict);
}
- FREE(conf);
+ _alpm_dep_free(conf);
return(match);
}
@@ -110,7 +127,7 @@ static void add_conflict(alpm_list_t **baddeps, const char *pkg1,
if(conflict && !_alpm_conflict_isin(conflict, *baddeps)) {
*baddeps = alpm_list_add(*baddeps, conflict);
} else {
- FREE(conflict);
+ _alpm_conflict_free(conflict);
}
}
@@ -200,9 +217,13 @@ alpm_list_t *_alpm_outerconflicts(pmdb_t *db, alpm_list_t *packages)
return(baddeps);
}
-/* Check for transaction conflicts */
-alpm_list_t *_alpm_checkconflicts(pmdb_t *db, alpm_list_t *packages) {
- return(alpm_list_join(_alpm_innerconflicts(packages), _alpm_outerconflicts(db, packages)));
+/** Check the package conflicts in a database
+ *
+ * @param db_local the database to check
+ * @return an alpm_list_t of pmconflict_t
+ */
+alpm_list_t SYMEXPORT *alpm_checkdbconflicts(pmdb_t *db_local) {
+ return(_alpm_innerconflicts(_alpm_db_get_pkgcache(db_local)));
}
/* Returns a alpm_list_t* of file conflicts.
@@ -299,15 +320,15 @@ static alpm_list_t *add_fileconflict(alpm_list_t *conflicts,
const char* name1, const char* name2)
{
pmfileconflict_t *conflict;
- MALLOC(conflict, sizeof(pmfileconflict_t), return(conflicts));
+ MALLOC(conflict, sizeof(pmfileconflict_t), RET_ERR(PM_ERR_MEMORY, NULL));
conflict->type = type;
- strncpy(conflict->target, name1, PKG_NAME_LEN);
- strncpy(conflict->file, filestr, CONFLICT_FILE_LEN);
+ STRDUP(conflict->target, name1, RET_ERR(PM_ERR_MEMORY, NULL));
+ STRDUP(conflict->file, filestr, RET_ERR(PM_ERR_MEMORY, NULL));
if(name2) {
- strncpy(conflict->ctarget, name2, PKG_NAME_LEN);
+ STRDUP(conflict->ctarget, name2, RET_ERR(PM_ERR_MEMORY, NULL));
} else {
- conflict->ctarget[0] = '\0';
+ conflict->ctarget = "";
}
conflicts = alpm_list_add(conflicts, conflict);
@@ -317,6 +338,16 @@ static alpm_list_t *add_fileconflict(alpm_list_t *conflicts,
return(conflicts);
}
+void _alpm_fileconflict_free(pmfileconflict_t *conflict)
+{
+ if(strlen(conflict->ctarget) > 0) {
+ FREE(conflict->ctarget);
+ }
+ FREE(conflict->file);;
+ FREE(conflict->target);
+ FREE(conflict);
+}
+
/* Find file conflicts that may occur during the transaction with two checks:
* 1: check every target against every target
* 2: check every target against the filesystem */
@@ -351,13 +382,13 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", (percent * 100),
numtargs, current);
/* CHECK 1: check every target against every target */
+ _alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s\n",
+ alpm_pkg_get_name(p1));
for(j = i->next; j; j = j->next) {
p2 = j->data;
if(!p2) {
continue;
}
- _alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s and %s\n",
- alpm_pkg_get_name(p1), alpm_pkg_get_name(p2));
tmpfiles = chk_fileconflicts(alpm_pkg_get_files(p1), alpm_pkg_get_files(p2));
if(tmpfiles) {
@@ -416,26 +447,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
if(!skip_conflict) {
_alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path);
- /* Make sure the possible conflict is not a symlink that points to a
- * path in the old package. This is kind of dirty with inode usage */
- /* TODO this seems ripe for a cleanup */
- if(dbpkg) {
- struct stat pkgbuf;
- char str[PATH_MAX+1];
- unsigned ok = 0;
- for(k = dbpkg->files; k; k = k->next) {
- snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data);
- if(!_alpm_lstat(str, &pkgbuf) && lsbuf.st_ino == pkgbuf.st_ino) {
- ok = 1;
- _alpm_log(PM_LOG_DEBUG, "conflict was a symlink: %s\n", path);
- break;
- }
- }
- if(ok == 1) {
- continue;
- }
- }
-
/* Look at all the targets to see if file has changed hands */
int resolved_conflict = 0; /* have we acted on this conflict? */
for(k = targets; k; k = k->next) {
diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h
index a846aace..71ed579d 100644
--- a/lib/libalpm/conflict.h
+++ b/lib/libalpm/conflict.h
@@ -23,27 +23,28 @@
#include "db.h"
#include "package.h"
-#define CONFLICT_FILE_LEN 512
-
struct __pmconflict_t {
- char package1[PKG_NAME_LEN];
- char package2[PKG_NAME_LEN];
+ char *package1;
+ char *package2;
};
struct __pmfileconflict_t {
- char target[PKG_NAME_LEN];
+ char *target;
pmfileconflicttype_t type;
- char file[CONFLICT_FILE_LEN];
- char ctarget[PKG_NAME_LEN];
+ char *file;
+ char *ctarget;
};
pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2);
+pmconflict_t *_alpm_conflict_dup(const pmconflict_t *conflict);
+void _alpm_conflict_free(pmconflict_t *conflict);
int _alpm_conflict_isin(pmconflict_t *needle, alpm_list_t *haystack);
alpm_list_t *_alpm_innerconflicts(alpm_list_t *packages);
alpm_list_t *_alpm_outerconflicts(pmdb_t *db, alpm_list_t *packages);
-alpm_list_t *_alpm_checkconflicts(pmdb_t *db, alpm_list_t *packages);
alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *root);
+void _alpm_fileconflict_free(pmfileconflict_t *conflict);
+
#endif /* _ALPM_CONFLICT_H */
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index 1485c34a..df16c3c9 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -39,8 +39,6 @@
#include "alpm_list.h"
#include "log.h"
#include "util.h"
-#include "error.h"
-#include "server.h"
#include "handle.h"
#include "cache.h"
#include "alpm.h"
@@ -190,14 +188,9 @@ int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url)
}
if(url && strlen(url)) {
- pmserver_t *server;
- if((server = _alpm_server_new(url)) == NULL) {
- /* pm_errno is set by _alpm_server_new */
- return(-1);
- }
- db->servers = alpm_list_add(db->servers, server);
- _alpm_log(PM_LOG_DEBUG, "adding new server to database '%s': protocol '%s', server '%s', path '%s'\n",
- db->treename, server->s_url->scheme, server->s_url->host, server->s_url->doc);
+ db->servers = alpm_list_add(db->servers, strdup(url));
+ _alpm_log(PM_LOG_DEBUG, "adding new server URL to database '%s': %s\n",
+ db->treename, url);
} else {
FREELIST(db->servers);
_alpm_log(PM_LOG_DEBUG, "serverlist flushed for '%s'\n", db->treename);
@@ -206,98 +199,6 @@ int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url)
return(0);
}
-/** Update a package database
- * @param force if true, then forces the update, otherwise update only in case
- * the database isn't up to date
- * @param db pointer to the package database to update
- * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
- * to date
- */
-int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
-{
- alpm_list_t *lp;
- char path[PATH_MAX];
- alpm_list_t *files = NULL;
- time_t newmtime = 0, lastupdate = 0;
- const char *dbpath;
- int ret;
-
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
- ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
- /* Verify we are in a transaction. This is done _mainly_ because we need a DB
- * lock - if we update without a db lock, we may kludge some other pacman
- * process that _has_ a lock.
- */
- ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
- ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
- ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1));
-
- if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
- RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
- }
-
- if(!force) {
- /* get the lastupdate time */
- lastupdate = _alpm_db_getlastupdate(db);
- if(lastupdate == 0) {
- _alpm_log(PM_LOG_DEBUG, "failed to get lastupdate time for %s\n",
- db->treename);
- }
- }
-
- /* build a one-element list */
- snprintf(path, PATH_MAX, "%s" DBEXT, db->treename);
- files = alpm_list_add(files, strdup(path));
-
- dbpath = alpm_option_get_dbpath();
-
- ret = _alpm_downloadfiles_forreal(db->servers, dbpath, files, lastupdate,
- &newmtime, NULL, 0);
- FREELIST(files);
- if(ret == 1) {
- /* mtimes match, do nothing */
- pm_errno = 0;
- return(1);
- } else if(ret == -1) {
- /* we use downloadLastErrString and downloadLastErrCode here, error returns from
- * libdownload */
- _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s [%d]\n",
- downloadLastErrString, downloadLastErrCode);
- RET_ERR(PM_ERR_DB_SYNC, -1);
- } else {
- if(newmtime != 0) {
- _alpm_log(PM_LOG_DEBUG, "sync: new mtime for %s: %ju\n",
- db->treename, (uintmax_t)newmtime);
- _alpm_db_setlastupdate(db, newmtime);
- }
- snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename);
-
- /* remove the old dir */
- _alpm_log(PM_LOG_DEBUG, "flushing database %s\n", db->path);
- for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
- pmpkg_t *pkg = lp->data;
- if(pkg && _alpm_db_remove(db, pkg) == -1) {
- _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s%s\n"), db->treename,
- alpm_pkg_get_name(pkg));
- RET_ERR(PM_ERR_DB_REMOVE, -1);
- }
- }
-
- /* Cache needs to be rebuild */
- _alpm_db_free_pkgcache(db);
-
- /* uncompress the sync database */
- if(_alpm_db_install(db, path) == -1) {
- return -1;
- }
- }
-
- return(0);
-}
-
/** Get the name of a package database
* @param db pointer to the package database
* @return the name of the package database, NULL on error
@@ -319,8 +220,7 @@ const char SYMEXPORT *alpm_db_get_name(const pmdb_t *db)
*/
const char SYMEXPORT *alpm_db_get_url(const pmdb_t *db)
{
- char path[PATH_MAX];
- pmserver_t *s;
+ char *url;
ALPM_LOG_FUNC;
@@ -328,10 +228,9 @@ const char SYMEXPORT *alpm_db_get_url(const pmdb_t *db)
ASSERT(handle != NULL, return(NULL));
ASSERT(db != NULL, return(NULL));
- s = (pmserver_t*)db->servers->data;
+ url = (char*)db->servers->data;
- snprintf(path, PATH_MAX, "%s://%s%s", s->s_url->scheme, s->s_url->host, s->s_url->doc);
- return strdup(path);
+ return(url);
}
@@ -367,23 +266,6 @@ alpm_list_t SYMEXPORT *alpm_db_getpkgcache(pmdb_t *db)
return(_alpm_db_get_pkgcache(db));
}
-/** Get the list of packages that a package provides
- * @param db pointer to the package database to get the package from
- * @param name name of the package
- * @return the list of packages on success, NULL on error
- */
-alpm_list_t SYMEXPORT *alpm_db_whatprovides(pmdb_t *db, const char *name)
-{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(db != NULL, return(NULL));
- ASSERT(name != NULL && strlen(name) != 0, return(NULL));
-
- return(_alpm_db_whatprovides(db, name));
-}
-
/** Get a group entry from a package database
* @param db pointer to the package database to get the group from
* @param name of the group
@@ -445,35 +327,31 @@ pmdb_t *_alpm_db_new(const char *dbpath, const char *treename)
CALLOC(db->path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
sprintf(db->path, "%s%s/", dbpath, treename);
-
- strncpy(db->treename, treename, PATH_MAX);
+ STRDUP(db->treename, treename, RET_ERR(PM_ERR_MEMORY, NULL));
return(db);
}
void _alpm_db_free(pmdb_t *db)
{
- alpm_list_t *tmp;
-
ALPM_LOG_FUNC;
/* cleanup pkgcache */
_alpm_db_free_pkgcache(db);
/* cleanup server list */
- for(tmp = db->servers; tmp; tmp = alpm_list_next(tmp)) {
- _alpm_server_free(tmp->data);
- }
- alpm_list_free(db->servers);
+ FREELIST(db->servers);
FREE(db->path);
+ FREE(db->treename);
FREE(db);
return;
}
-int _alpm_db_cmp(const void *db1, const void *db2)
+int _alpm_db_cmp(const void *d1, const void *d2)
{
- ALPM_LOG_FUNC;
- return(strcmp(((pmdb_t *)db1)->treename, ((pmdb_t *)db2)->treename));
+ pmdb_t *db1 = (pmdb_t *)db1;
+ pmdb_t *db2 = (pmdb_t *)db2;
+ return(strcmp(db1->treename, db2->treename));
}
alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
@@ -500,18 +378,16 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
for(j = _alpm_db_get_pkgcache(db); j; j = j->next) {
pmpkg_t *pkg = j->data;
const char *matched = NULL;
+ const char *name = alpm_pkg_get_name(pkg);
+ const char *desc = alpm_pkg_get_desc(pkg);
- /* check name */
- if (regexec(&reg, alpm_pkg_get_name(pkg), 0, 0, 0) == 0) {
- matched = alpm_pkg_get_name(pkg);
- }
- /* check plain text name */
- else if (strstr(alpm_pkg_get_name(pkg), targ)) {
- matched = alpm_pkg_get_name(pkg);
+ /* check name as regex AND as plain text */
+ if(name && (regexec(&reg, name, 0, 0, 0) == 0 || strstr(name, targ))) {
+ matched = name;
}
/* check desc */
- else if (regexec(&reg, alpm_pkg_get_desc(pkg), 0, 0, 0) == 0) {
- matched = alpm_pkg_get_desc(pkg);
+ else if (desc && regexec(&reg, desc, 0, 0, 0) == 0) {
+ matched = desc;
}
/* check provides */
/* TODO: should we be doing this, and should we print something
@@ -641,47 +517,4 @@ pmdb_t *_alpm_db_register_sync(const char *treename)
return(db);
}
-/* helper function for alpm_list_find and _alpm_db_whatprovides
- *
- * @return "provision.name" == needle (as string)
- */
-int _alpm_prov_cmp(const void *provision, const void *needle)
-{
- char *tmpptr;
- char *provname = strdup(provision);
- int retval = 0;
- tmpptr = strchr(provname, '=');
-
- if(tmpptr != NULL) { /* provision-version */
- *tmpptr='\0';
- }
- retval = strcmp(provname, needle);
- free(provname);
- return(retval);
-}
-
-/* return a alpm_list_t of packages in "db" that provide "package"
- */
-alpm_list_t *_alpm_db_whatprovides(pmdb_t *db, const char *package)
-{
- alpm_list_t *pkgs = NULL;
- alpm_list_t *lp;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || package == NULL || strlen(package) == 0) {
- return(NULL);
- }
-
- for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
- pmpkg_t *info = lp->data;
-
- if(alpm_list_find(alpm_pkg_get_provides(info), (const void *)package, _alpm_prov_cmp)) {
- pkgs = alpm_list_add(pkgs, info);
- }
- }
-
- return(pkgs);
-}
-
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index 8c8c9bd7..eb0af1ae 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -40,7 +40,7 @@ typedef enum _pmdbinfrq_t {
/* Database */
struct __pmdb_t {
char *path;
- char treename[PATH_MAX];
+ char *treename;
void *handle;
alpm_list_t *pkgcache;
alpm_list_t *grpcache;
@@ -55,21 +55,13 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);
pmdb_t *_alpm_db_register_local(void);
pmdb_t *_alpm_db_register_sync(const char *treename);
-/* Provision */
-int _alpm_prov_cmp(const void *provision, const void *needle);
-alpm_list_t *_alpm_db_whatprovides(pmdb_t *db, const char *package);
-
/* be.c, backend specific calls */
-int _alpm_db_install(pmdb_t *db, const char *dbfile);
int _alpm_db_open(pmdb_t *db);
void _alpm_db_close(pmdb_t *db);
-void _alpm_db_rewind(pmdb_t *db);
-pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target);
+int _alpm_db_populate(pmdb_t *db);
int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
int _alpm_db_remove(pmdb_t *db, pmpkg_t *info);
-time_t _alpm_db_getlastupdate(const pmdb_t *db);
-int _alpm_db_setlastupdate(const pmdb_t *db, time_t time);
#endif /* _ALPM_DB_H */
diff --git a/lib/libalpm/delta.c b/lib/libalpm/delta.c
index 3d33c595..fdb4d99b 100644
--- a/lib/libalpm/delta.c
+++ b/lib/libalpm/delta.c
@@ -1,7 +1,7 @@
/*
* delta.c
*
- * Copyright (c) 2007 by Judd Vinet <jvinet@zeroflux.org>
+ * Copyright (c) 2007-2008 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,14 +21,14 @@
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
/* libalpm */
#include "delta.h"
-#include "error.h"
+#include "alpm_list.h"
#include "util.h"
#include "log.h"
-#include "alpm_list.h"
-#include "alpm.h"
+#include "graph.h"
/** \addtogroup alpm_deltas Delta Functions
* @brief Functions to manipulate libalpm deltas
@@ -37,200 +37,222 @@
const char SYMEXPORT *alpm_delta_get_from(pmdelta_t *delta)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
ASSERT(delta != NULL, return(NULL));
-
return(delta->from);
}
-const char SYMEXPORT *alpm_delta_get_to(pmdelta_t *delta)
+const char SYMEXPORT *alpm_delta_get_from_md5sum(pmdelta_t *delta)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
ASSERT(delta != NULL, return(NULL));
+ return(delta->from_md5);
+}
+const char SYMEXPORT *alpm_delta_get_to(pmdelta_t *delta)
+{
+ ASSERT(delta != NULL, return(NULL));
return(delta->to);
}
-unsigned long SYMEXPORT alpm_delta_get_size(pmdelta_t *delta)
+const char SYMEXPORT *alpm_delta_get_to_md5sum(pmdelta_t *delta)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(delta != NULL, return(-1));
-
- return(delta->size);
+ ASSERT(delta != NULL, return(NULL));
+ return(delta->to_md5);
}
const char SYMEXPORT *alpm_delta_get_filename(pmdelta_t *delta)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
ASSERT(delta != NULL, return(NULL));
-
- return(delta->filename);
+ return(delta->delta);
}
const char SYMEXPORT *alpm_delta_get_md5sum(pmdelta_t *delta)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
ASSERT(delta != NULL, return(NULL));
+ return(delta->delta_md5);
+}
- return(delta->md5sum);
+unsigned long SYMEXPORT alpm_delta_get_size(pmdelta_t *delta)
+{
+ ASSERT(delta != NULL, return(-1));
+ return(delta->delta_size);
}
/** @} */
-/** Calculates the combined size of a list of delta files.
- *
- * @param deltas the list of pmdelta_t * objects
- *
- * @return the combined size
- */
-unsigned long _alpm_delta_path_size(alpm_list_t *deltas)
+static alpm_list_t *delta_graph_init(alpm_list_t *deltas)
{
- unsigned long sum = 0;
- alpm_list_t *dlts = deltas;
-
- while(dlts) {
- pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts);
- sum += d->size;
+ alpm_list_t *i, *j;
+ alpm_list_t *vertices = NULL;
+ /* create the vertices */
+ for(i = deltas; i; i = i->next) {
+ char *fpath, *md5sum;
+ pmgraph_t *v = _alpm_graph_new();
+ pmdelta_t *vdelta = i->data;
+ vdelta->download_size = vdelta->delta_size;
+ v->weight = ULONG_MAX;
+
+ /* determine whether the delta file already exists */
+ fpath = _alpm_filecache_find(vdelta->delta);
+ md5sum = alpm_get_md5sum(fpath);
+ if(fpath && md5sum && strcmp(md5sum, vdelta->delta_md5) == 0) {
+ vdelta->download_size = 0;
+ }
+ FREE(fpath);
+ FREE(md5sum);
+
+ /* determine whether a base 'from' file exists */
+ fpath = _alpm_filecache_find(vdelta->from);
+ md5sum = alpm_get_md5sum(fpath);
+ if(fpath && md5sum && strcmp(md5sum, vdelta->from_md5) == 0) {
+ v->weight = vdelta->download_size;
+ }
+ FREE(fpath);
+ FREE(md5sum);
- dlts = alpm_list_next(dlts);
+ v->data = vdelta;
+ vertices = alpm_list_add(vertices, v);
}
- return(sum);
+ /* compute the edges */
+ for(i = vertices; i; i = i->next) {
+ pmgraph_t *v_i = i->data;
+ pmdelta_t *d_i = v_i->data;
+ /* loop a second time so we make all possible comparisons */
+ for(j = vertices; j; j = j->next) {
+ pmgraph_t *v_j = j->data;
+ pmdelta_t *d_j = v_j->data;
+ /* We want to create a delta tree like the following:
+ * 1_to_2
+ * |
+ * 1_to_3 2_to_3
+ * \ /
+ * 3_to_4
+ * If J 'from' is equal to I 'to', then J is a child of I.
+ * */
+ if(strcmp(d_j->from, d_i->to) == 0
+ && strcmp(d_j->from_md5, d_i->to_md5) == 0) {
+ v_i->children = alpm_list_add(v_i->children, v_j);
+ }
+ }
+ v_i->childptr = v_i->children;
+ }
+ return(vertices);
}
-/** Calculates the combined size of a list of delta files that are not
- * in the cache.
- *
- * @param deltas the list of pmdelta_t * objects
- *
- * @return the combined size
- */
-unsigned long _alpm_delta_path_size_uncached(alpm_list_t *deltas)
-{
- unsigned long sum = 0;
- alpm_list_t *dlts = deltas;
-
- while(dlts) {
- pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts);
- char *fname = _alpm_filecache_find(d->filename);
+static unsigned long delta_vert(alpm_list_t *vertices,
+ const char *to, const char *to_md5, alpm_list_t **path) {
+ alpm_list_t *i;
+ pmgraph_t *v;
+ while(1) {
+ v = NULL;
+ /* find the smallest vertice not visited yet */
+ for(i = vertices; i; i = i->next) {
+ pmgraph_t *v_i = i->data;
+
+ if(v_i->state == -1) {
+ continue;
+ }
- if(!fname) {
- sum += d->size;
+ if(v == NULL || v_i->weight < v->weight) {
+ v = v_i;
+ }
+ }
+ if(v == NULL || v->weight == ULONG_MAX) {
+ break;
}
- FREE(fname);
+ v->state = -1;
- dlts = alpm_list_next(dlts);
- }
+ v->childptr = v->children;
+ while(v->childptr) {
+ pmgraph_t *v_c = v->childptr->data;
+ pmdelta_t *d_c = v_c->data;
+ if(v_c->weight > v->weight + d_c->download_size) {
+ v_c->weight = v->weight + d_c->download_size;
+ v_c->parent = v;
+ }
- return(sum);
-}
+ v->childptr = (v->childptr)->next;
-/** Calculates the shortest path from one version to another.
- *
- * The shortest path is defined as the path with the smallest combined
- * size, not the length of the path.
- *
- * The algorithm is based on Dijkstra's shortest path algorithm.
- *
- * @param deltas the list of pmdelta_t * objects that a package has
- * @param from the version to start from
- * @param to the version to end at
- * @param path the current path
- *
- * @return the list of pmdelta_t * objects that has the smallest size.
- * NULL (the empty list) is returned if there is no path between the
- * versions.
- */
-static alpm_list_t *shortest_delta_path(alpm_list_t *deltas,
- const char *from, const char *to, alpm_list_t *path)
-{
- alpm_list_t *d;
- alpm_list_t *shortest = NULL;
-
- /* Found the 'to' version, this is a good path so return it. */
- if(strcmp(from, to) == 0) {
- return(path);
+ }
}
- for(d = deltas; d; d = alpm_list_next(d)) {
- pmdelta_t *v = alpm_list_getdata(d);
+ v = NULL;
+ unsigned long bestsize = 0;
- /* If this vertex has already been visited in the path, go to the
- * next vertex. */
- if(alpm_list_find_ptr(path, v)) {
- continue;
- }
+ for(i = vertices; i; i = i->next) {
+ pmgraph_t *v_i = i->data;
+ pmdelta_t *d_i = v_i->data;
- /* Once we find a vertex that starts at the 'from' version,
- * recursively find the shortest path using the 'to' version of this
- * current vertex as the 'from' version in the function call. */
- if(strcmp(v->from, from) == 0) {
- alpm_list_t *newpath = alpm_list_copy(path);
- newpath = alpm_list_add(newpath, v);
- newpath = shortest_delta_path(deltas, v->to, to, newpath);
-
- if(newpath != NULL) {
- /* The path returned works, now use it unless there is already a
- * shorter path found. */
- if(shortest == NULL) {
- shortest = newpath;
- } else if(_alpm_delta_path_size(shortest) > _alpm_delta_path_size(newpath)) {
- alpm_list_free(shortest);
- shortest = newpath;
- } else {
- alpm_list_free(newpath);
- }
+ if(strcmp(d_i->to, to) == 0
+ || strcmp(d_i->to_md5, to_md5) == 0) {
+ if(v == NULL || v_i->weight < v->weight) {
+ v = v_i;
+ bestsize = v->weight;
}
}
}
- alpm_list_free(path);
+ alpm_list_t *rpath = NULL;
+ while(v != NULL) {
+ pmdelta_t *vdelta = v->data;
+ rpath = alpm_list_add(rpath, vdelta);
+ v = v->parent;
+ }
+ *path = alpm_list_reverse(rpath);
+ alpm_list_free(rpath);
- return(shortest);
+ return(bestsize);
}
/** Calculates the shortest path from one version to another.
- *
* The shortest path is defined as the path with the smallest combined
* size, not the length of the path.
- *
- * @param deltas the list of pmdelta_t * objects that a package has
- * @param from the version to start from
- * @param to the version to end at
- *
- * @return the list of pmdelta_t * objects that has the smallest size.
- * NULL (the empty list) is returned if there is no path between the
- * versions.
+ * @param deltas the list of pmdelta_t * objects that a file has
+ * @param to the file to start the search at
+ * @param to_md5 the md5sum of the above named file
+ * @param path the pointer to a list location where pmdelta_t * objects that
+ * have the smallest size are placed. NULL is set if there is no path
+ * possible with the files available.
+ * @return the size of the path stored, or ULONG_MAX if path is unfindable
*/
-alpm_list_t *_alpm_shortest_delta_path(alpm_list_t *deltas, const char *from,
- const char *to)
+unsigned long _alpm_shortest_delta_path(alpm_list_t *deltas,
+ const char *to, const char *to_md5, alpm_list_t **path)
{
- alpm_list_t *path = NULL;
+ alpm_list_t *bestpath = NULL;
+ alpm_list_t *vertices;
+ unsigned long bestsize = ULONG_MAX;
+
+ ALPM_LOG_FUNC;
+
+ if(deltas == NULL) {
+ *path = NULL;
+ return(bestsize);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "started delta shortest-path search\n");
+
+ vertices = delta_graph_init(deltas);
+
+ bestsize = delta_vert(vertices, to, to_md5, &bestpath);
- path = shortest_delta_path(deltas, from, to, path);
+ _alpm_log(PM_LOG_DEBUG, "delta shortest-path search complete\n");
- return(path);
+ alpm_list_free_inner(vertices, _alpm_graph_free);
+ alpm_list_free(vertices);
+
+ *path = bestpath;
+ return(bestsize);
}
/** Parses the string representation of a pmdelta_t object.
- *
* This function assumes that the string is in the correct format.
- *
+ * This format is as follows:
+ * $oldfile $oldmd5 $newfile $newmd5 $deltafile $deltamd5 $deltasize
* @param line the string to parse
- *
* @return A pointer to the new pmdelta_t object
*/
+/* TODO this does not really belong here, but in a parsing lib */
pmdelta_t *_alpm_delta_parse(char *line)
{
pmdelta_t *delta;
@@ -241,26 +263,47 @@ pmdelta_t *_alpm_delta_parse(char *line)
tmp2 = tmp;
tmp = strchr(tmp, ' ');
*(tmp++) = '\0';
- strncpy(delta->from, tmp2, DLT_VERSION_LEN);
+ STRDUP(delta->from, tmp2, RET_ERR(PM_ERR_MEMORY, NULL));
tmp2 = tmp;
tmp = strchr(tmp, ' ');
*(tmp++) = '\0';
- strncpy(delta->to, tmp2, DLT_VERSION_LEN);
+ STRDUP(delta->from_md5, tmp2, RET_ERR(PM_ERR_MEMORY, NULL));
tmp2 = tmp;
tmp = strchr(tmp, ' ');
*(tmp++) = '\0';
- delta->size = atol(tmp2);
+ STRDUP(delta->to, tmp2, RET_ERR(PM_ERR_MEMORY, NULL));
tmp2 = tmp;
tmp = strchr(tmp, ' ');
*(tmp++) = '\0';
- strncpy(delta->filename, tmp2, DLT_FILENAME_LEN);
+ STRDUP(delta->to_md5, tmp2, RET_ERR(PM_ERR_MEMORY, NULL));
- strncpy(delta->md5sum, tmp, DLT_MD5SUM_LEN);
+ tmp2 = tmp;
+ tmp = strchr(tmp, ' ');
+ *(tmp++) = '\0';
+ STRDUP(delta->delta, tmp2, RET_ERR(PM_ERR_MEMORY, NULL));
+
+ tmp2 = tmp;
+ tmp = strchr(tmp, ' ');
+ *(tmp++) = '\0';
+ STRDUP(delta->delta_md5, tmp2, RET_ERR(PM_ERR_MEMORY, NULL));
+
+ delta->delta_size = atol(tmp);
return(delta);
}
+void _alpm_delta_free(pmdelta_t *delta)
+{
+ FREE(delta->from);
+ FREE(delta->from_md5);
+ FREE(delta->to);
+ FREE(delta->to_md5);
+ FREE(delta->delta);
+ FREE(delta->delta_md5);
+ FREE(delta);
+}
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h
index 3065d4d1..33d47e1e 100644
--- a/lib/libalpm/delta.h
+++ b/lib/libalpm/delta.h
@@ -1,7 +1,7 @@
/*
* delta.h
*
- * Copyright (c) 2007 by Judd Vinet <jvinet@zeroflux.org>
+ * Copyright (c) 2007-2008 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,22 +21,29 @@
#include "alpm.h"
-#define DLT_FILENAME_LEN 512
-#define DLT_VERSION_LEN 64
-#define DLT_MD5SUM_LEN 33
-
struct __pmdelta_t {
- char from[DLT_VERSION_LEN];
- char to[DLT_VERSION_LEN];
- unsigned long size;
- char filename[DLT_FILENAME_LEN];
- char md5sum[DLT_MD5SUM_LEN];
+ /** filename of the 'before' file */
+ char *from;
+ /** md5sum of the 'before' file */
+ char *from_md5;
+ /** filename of the 'after' file */
+ char *to;
+ /** md5sum of the 'after' file */
+ char *to_md5;
+ /** filename of the delta patch */
+ char *delta;
+ /** md5sum of the delta file */
+ char *delta_md5;
+ /** filesize of the delta file */
+ unsigned long delta_size;
+ /** download filesize of the delta file */
+ unsigned long download_size;
};
-unsigned long _alpm_delta_path_size(alpm_list_t *deltas);
-unsigned long _alpm_delta_path_size_uncached(alpm_list_t *deltas);
pmdelta_t *_alpm_delta_parse(char *line);
-alpm_list_t *_alpm_shortest_delta_path(alpm_list_t *deltas, const char *from, const char *to);
+void _alpm_delta_free(pmdelta_t *delta);
+unsigned long _alpm_shortest_delta_path(alpm_list_t *deltas,
+ const char *to, const char *to_md5, alpm_list_t **path);
#endif /* _ALPM_DELTA_H */
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c
index b967243d..37e99162 100644
--- a/lib/libalpm/deps.c
+++ b/lib/libalpm/deps.c
@@ -30,37 +30,21 @@
#include "alpm_list.h"
#include "util.h"
#include "log.h"
-#include "error.h"
+#include "graph.h"
#include "package.h"
#include "db.h"
#include "cache.h"
#include "handle.h"
-static pmgraph_t *_alpm_graph_new(void)
+void _alpm_dep_free(pmdepend_t *dep)
{
- pmgraph_t *graph = NULL;
-
- MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL));
-
- if(graph) {
- graph->state = 0;
- graph->data = NULL;
- graph->parent = NULL;
- graph->children = NULL;
- graph->childptr = NULL;
- }
- return(graph);
-}
-
-static void _alpm_graph_free(void *data)
-{
- pmgraph_t *graph = data;
- alpm_list_free(graph->children);
- free(graph);
+ FREE(dep->name);
+ FREE(dep->version);
+ FREE(dep);
}
-pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod,
- const char *depname, const char *depversion)
+pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep,
+ const char *causingpkg)
{
pmdepmissing_t *miss;
@@ -68,24 +52,27 @@ pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod,
MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL));
- strncpy(miss->target, target, PKG_NAME_LEN);
- miss->depend.mod = depmod;
- strncpy(miss->depend.name, depname, PKG_NAME_LEN);
- if(depversion) {
- strncpy(miss->depend.version, depversion, PKG_VERSION_LEN);
- } else {
- miss->depend.version[0] = 0;
- }
+ STRDUP(miss->target, target, RET_ERR(PM_ERR_MEMORY, NULL));
+ miss->depend = _alpm_dep_dup(dep);
+ STRDUP(miss->causingpkg, causingpkg, RET_ERR(PM_ERR_MEMORY, NULL));
return(miss);
}
+void _alpm_depmiss_free(pmdepmissing_t *miss)
+{
+ _alpm_dep_free(miss->depend);
+ FREE(miss->target);
+ FREE(miss->causingpkg);
+ FREE(miss);
+}
+
/* Convert a list of pmpkg_t * to a graph structure,
* with a edge for each dependency.
* Returns a list of vertices (one vertex = one package)
* (used by alpm_sortbydeps)
*/
-static alpm_list_t *_alpm_graph_init(alpm_list_t *targets)
+static alpm_list_t *dep_graph_init(alpm_list_t *targets)
{
alpm_list_t *i, *j, *k;
alpm_list_t *vertices = NULL;
@@ -121,20 +108,19 @@ static alpm_list_t *_alpm_graph_init(alpm_list_t *targets)
/* Re-order a list of target packages with respect to their dependencies.
*
- * Example (PM_TRANS_TYPE_ADD):
+ * Example (reverse == 0):
* A depends on C
* B depends on A
* Target order is A,B,C,D
*
* Should be re-ordered to C,A,B,D
*
- * mode should be either PM_TRANS_TYPE_ADD or PM_TRANS_TYPE_REMOVE. This
- * affects the dependency order sortbydeps() will use.
+ * if reverse is > 0, the dependency order will be reversed.
*
* This function returns the new alpm_list_t* target list.
*
*/
-alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
+alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse)
{
alpm_list_t *newtargs = NULL;
alpm_list_t *vertices = NULL;
@@ -149,7 +135,7 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
_alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n");
- vertices = _alpm_graph_init(targets);
+ vertices = dep_graph_init(targets);
vptr = vertices;
vertex = vertices->data;
@@ -169,7 +155,7 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
pmpkg_t *vertexpkg = vertex->data;
pmpkg_t *childpkg = nextchild->data;
_alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n"));
- if(mode == PM_TRANS_TYPE_REMOVE) {
+ if(reverse) {
_alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name);
} else {
_alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name);
@@ -194,8 +180,8 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
_alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n");
- if(mode == PM_TRANS_TYPE_REMOVE) {
- /* we're removing packages, so reverse the order */
+ if(reverse) {
+ /* reverse the order */
alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
/* free the old one */
alpm_list_free(newtargs);
@@ -208,10 +194,55 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
return(newtargs);
}
-/* Little helper function for alpm_list_find */
-static int satisfycmp(const void *pkg, const void *depend)
+alpm_list_t *_alpm_find_dep_satisfiers(alpm_list_t *pkgs, pmdepend_t *dep)
{
- return(!alpm_depcmp((pmpkg_t*) pkg, (pmdepend_t*) depend));
+ alpm_list_t *i, *ret = NULL;
+
+ for(i = pkgs; i; i = alpm_list_next(i)) {
+ pmpkg_t *pkg = i->data;
+ if(alpm_depcmp(pkg, dep)) {
+ ret = alpm_list_add(ret, pkg);
+ }
+ }
+ return(ret);
+}
+
+/** Find packages in a list that provide a given package.
+ * @param pkgs an alpm_list_t* of package to search
+ * @param pkgname the name of the package
+ * @return an alpm_list_t* of packages that provide pkgname
+ */
+alpm_list_t SYMEXPORT *alpm_find_pkg_satisfiers(alpm_list_t *pkgs, const char *pkgname)
+{
+ pmdepend_t *dep = _alpm_splitdep(pkgname);
+ alpm_list_t *res = _alpm_find_dep_satisfiers(pkgs, dep);
+ _alpm_dep_free(dep);
+ return(res);
+}
+
+/** Checks dependencies and returns missing ones in a list.
+ * Dependencies can include versions with depmod operators.
+ * @param db pointer to the local package database
+ * @param targets an alpm_list_t* of dependencies strings to satisfy
+ * @return an alpm_list_t* of missing dependencies strings
+ */
+alpm_list_t SYMEXPORT *alpm_deptest(pmdb_t *db, alpm_list_t *targets)
+{
+ alpm_list_t *i, *ret = NULL;
+
+ for(i = targets; i; i = alpm_list_next(i)) {
+ pmdepend_t *dep;
+ char *target;
+
+ target = alpm_list_getdata(i);
+ dep = _alpm_splitdep(target);
+
+ if(!_alpm_find_dep_satisfiers(_alpm_db_get_pkgcache(db), dep)) {
+ ret = alpm_list_add(ret, target);
+ }
+ _alpm_dep_free(dep);
+ }
+ return(ret);
}
/** Checks dependencies and returns missing ones in a list.
@@ -257,15 +288,14 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps,
pmdepend_t *depend = j->data;
/* 1. we check the upgrade list */
/* 2. we check database for untouched satisfying packages */
- if(!alpm_list_find(upgrade, depend, satisfycmp) &&
- !alpm_list_find(dblist, depend, satisfycmp)) {
+ if(!_alpm_find_dep_satisfiers(upgrade, depend) &&
+ !_alpm_find_dep_satisfiers(dblist, depend)) {
/* Unsatisfied dependency in the upgrade list */
char *missdepstring = alpm_dep_get_string(depend);
_alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
missdepstring, alpm_pkg_get_name(tp));
free(missdepstring);
- miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend->mod,
- depend->name, depend->version);
+ miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend, "");
baddeps = alpm_list_add(baddeps, miss);
}
}
@@ -278,18 +308,18 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps,
pmpkg_t *lp = i->data;
for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
pmdepend_t *depend = j->data;
+ pmpkg_t *causingpkg = alpm_list_getdata(_alpm_find_dep_satisfiers(modified, depend));
/* we won't break this depend, if it is already broken, we ignore it */
/* 1. check upgrade list for satisfiers */
/* 2. check dblist for satisfiers */
- if(alpm_list_find(modified, depend, satisfycmp) &&
- !alpm_list_find(upgrade, depend, satisfycmp) &&
- !alpm_list_find(dblist, depend, satisfycmp)) {
+ if(causingpkg &&
+ !_alpm_find_dep_satisfiers(upgrade, depend) &&
+ !_alpm_find_dep_satisfiers(dblist, depend)) {
char *missdepstring = alpm_dep_get_string(depend);
_alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
missdepstring, alpm_pkg_get_name(lp));
free(missdepstring);
- miss = _alpm_depmiss_new(lp->name, depend->mod,
- depend->name, depend->version);
+ miss = _alpm_depmiss_new(lp->name, depend, alpm_pkg_get_name(causingpkg));
baddeps = alpm_list_add(baddeps, miss);
}
}
@@ -309,7 +339,7 @@ static int dep_vercmp(const char *version1, pmdepmod_t mod,
if(mod == PM_DEP_MOD_ANY) {
equal = 1;
} else {
- int cmp = _alpm_versioncmp(version1, version2);
+ int cmp = alpm_pkg_vercmp(version1, version2);
switch(mod) {
case PM_DEP_MOD_EQ: equal = (cmp == 0); break;
case PM_DEP_MOD_GE: equal = (cmp >= 0); break;
@@ -356,7 +386,7 @@ int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
return(satisfy);
}
-pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
+pmdepend_t *_alpm_splitdep(const char *depstring)
{
pmdepend_t *depend;
char *ptr = NULL;
@@ -365,9 +395,9 @@ pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
if(depstring == NULL) {
return(NULL);
}
- newstr = strdup(depstring);
+ STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL));
- MALLOC(depend, sizeof(pmdepend_t), return(NULL));
+ CALLOC(depend, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));
/* Find a version comparator if one exists. If it does, set the type and
* increment the ptr accordingly so we can copy the right strings. */
@@ -391,25 +421,36 @@ pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
depend->mod = PM_DEP_MOD_GT;
*ptr = '\0';
ptr += 1;
-
} else {
- /* no version specified - copy in the name and return it */
+ /* no version specified - copy the name and return it */
depend->mod = PM_DEP_MOD_ANY;
- strncpy(depend->name, newstr, PKG_NAME_LEN);
- depend->version[0] = '\0';
+ STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
+ depend->version = NULL;
free(newstr);
return(depend);
}
/* if we get here, we have a version comparator, copy the right parts
* to the right places */
- strncpy(depend->name, newstr, PKG_NAME_LEN);
- strncpy(depend->version, ptr, PKG_VERSION_LEN);
+ STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
+ STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL));
free(newstr);
return(depend);
}
+pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep)
+{
+ pmdepend_t *newdep;
+ CALLOC(newdep, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));
+
+ STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL));
+ STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL));
+ newdep->mod = dep->mod;
+
+ return(newdep);
+}
+
/* These parameters are messy. We check if this package, given a list of
* targets and a db is safe to remove. We do NOT remove it if it is in the
* target list, or if if the package was explictly installed and
@@ -417,9 +458,9 @@ pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets,
int include_explicit)
{
- alpm_list_t *i, *requiredby;
+ alpm_list_t *i, *j;
- if(_alpm_pkg_find(alpm_pkg_get_name(pkg), targets)) {
+ if(_alpm_pkg_find(targets, alpm_pkg_get_name(pkg))) {
return(0);
}
@@ -439,15 +480,17 @@ static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets,
* if checkdeps detected it would break something */
/* see if other packages need it */
- requiredby = alpm_pkg_compute_requiredby(pkg);
- for(i = requiredby; i; i = i->next) {
- pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data);
- if(reqpkg && !_alpm_pkg_find(alpm_pkg_get_name(reqpkg), targets)) {
- FREELIST(requiredby);
- return(0);
+ for(i = _alpm_db_get_pkgcache(db); i; i = i->next) {
+ pmpkg_t *lpkg = i->data;
+ for(j = alpm_pkg_get_depends(lpkg); j; j = j->next) {
+ if(alpm_depcmp(pkg, j->data)) {
+ if(!_alpm_pkg_find(targets, lpkg->name)) {
+ return(0);
+ }
+ break;
+ }
}
}
- FREELIST(requiredby);
/* it's ok to remove */
return(1);
@@ -523,7 +566,7 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
for(i = deps; i; i = i->next) {
int found = 0;
pmdepmissing_t *miss = i->data;
- pmdepend_t *missdep = &(miss->depend);
+ pmdepend_t *missdep = alpm_miss_get_dep(miss);
pmpkg_t *sync = NULL;
/* check if one of the packages in *list already satisfies this dependency */
@@ -548,13 +591,15 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
if(!sync) {
continue;
}
- found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
+ found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(remove, alpm_pkg_get_name(sync))
+ && !_alpm_pkg_find(*list, alpm_pkg_get_name(sync));
if(!found) {
continue;
}
/* If package is in the ignorepkg list, ask before we pull it */
if(_alpm_pkg_should_ignore(sync)) {
- pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
+ pmpkg_t *dummypkg = _alpm_pkg_new();
+ STRDUP(dummypkg->name, miss->target, RET_ERR(PM_ERR_MEMORY, -1));
QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
_alpm_pkg_free(dummypkg);
}
@@ -570,12 +615,14 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
continue;
}
found = alpm_depcmp(sync, missdep) && strcmp(sync->name, missdep->name)
- && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
+ && !_alpm_pkg_find(remove, alpm_pkg_get_name(sync))
+ && !_alpm_pkg_find(*list, alpm_pkg_get_name(sync));
if(!found) {
continue;
}
if(_alpm_pkg_should_ignore(sync)) {
- pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
+ pmpkg_t *dummypkg = _alpm_pkg_new();
+ STRDUP(dummypkg->name, miss->target, RET_ERR(PM_ERR_MEMORY, -1));
QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
_alpm_pkg_free(dummypkg);
}
@@ -611,7 +658,8 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
_alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n");
- FREELIST(deps);
+ alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
+ alpm_list_free(deps);
return(0);
@@ -627,7 +675,17 @@ const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss)
/* Sanity checks */
ASSERT(miss != NULL, return(NULL));
- return miss->target;
+ return(miss->target);
+}
+
+const char SYMEXPORT *alpm_miss_get_causingpkg(const pmdepmissing_t *miss)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(miss != NULL, return(NULL));
+
+ return miss->causingpkg;
}
pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss)
@@ -637,7 +695,7 @@ pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss)
/* Sanity checks */
ASSERT(miss != NULL, return(NULL));
- return &(miss->depend);
+ return(miss->depend);
}
pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep)
@@ -647,7 +705,7 @@ pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep)
/* Sanity checks */
ASSERT(dep != NULL, return(-1));
- return dep->mod;
+ return(dep->mod);
}
const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep)
@@ -657,7 +715,7 @@ const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep)
/* Sanity checks */
ASSERT(dep != NULL, return(NULL));
- return dep->name;
+ return(dep->name);
}
const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
@@ -667,7 +725,7 @@ const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
/* Sanity checks */
ASSERT(dep != NULL, return(NULL));
- return dep->version;
+ return(dep->version);
}
/** Reverse of splitdep; make a dep string from a pmdepend_t struct.
@@ -677,7 +735,7 @@ const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
*/
char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep)
{
- char *opr, *str = NULL;
+ char *name, *opr, *ver, *str = NULL;
size_t len;
ALPM_LOG_FUNC;
@@ -685,6 +743,12 @@ char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep)
/* Sanity checks */
ASSERT(dep != NULL, return(NULL));
+ if(dep->name) {
+ name = dep->name;
+ } else {
+ name = "";
+ }
+
switch(dep->mod) {
case PM_DEP_MOD_ANY:
opr = "";
@@ -709,11 +773,18 @@ char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep)
break;
}
+ if(dep->version) {
+ ver = dep->version;
+ } else {
+ ver = "";
+ }
+
/* we can always compute len and print the string like this because opr
- * and ver will be empty when PM_DEP_MOD_ANY is the depend type */
- len = strlen(dep->name) + strlen(opr) + strlen(dep->version) + 1;
+ * and ver will be empty when PM_DEP_MOD_ANY is the depend type. the
+ * reassignments above also ensure we do not do a strlen(NULL). */
+ len = strlen(name) + strlen(opr) + strlen(ver) + 1;
MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL));
- snprintf(str, len, "%s%s%s", dep->name, opr, dep->version);
+ snprintf(str, len, "%s%s%s", name, opr, ver);
return(str);
}
diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h
index 75cbb5bc..70badfd9 100644
--- a/lib/libalpm/deps.h
+++ b/lib/libalpm/deps.h
@@ -29,31 +29,29 @@
/* Dependency */
struct __pmdepend_t {
pmdepmod_t mod;
- char name[PKG_NAME_LEN];
- char version[PKG_VERSION_LEN];
+ char *name;
+ char *version;
};
/* Missing dependency */
struct __pmdepmissing_t {
- char target[PKG_NAME_LEN];
- pmdepend_t depend;
+ char *target;
+ pmdepend_t *depend;
+ char *causingpkg; /* this is used in case of remove dependency error only */
};
-/* Graphs */
-struct __pmgraph_t {
- int state; /* 0: untouched, -1: entered, other: leaving time */
- void *data;
- struct __pmgraph_t *parent; /* where did we come from? */
- alpm_list_t *children;
- alpm_list_t *childptr; /* points to a child in children list */
-};
-
-pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod,
- const char *depname, const char *depversion);
-alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode);
+void _alpm_dep_free(pmdepend_t *dep);
+pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep);
+pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep,
+ const char *causinpkg);
+void _alpm_depmiss_free(pmdepmissing_t *miss);
+alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse);
void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit);
int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
- alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t **data);
+ alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t
+ **data);
+pmdepend_t *_alpm_splitdep(const char *depstring);
+alpm_list_t *_alpm_find_dep_satisfiers(alpm_list_t *pkgs, pmdepend_t *dep);
#endif /* _ALPM_DEPS_H */
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
new file mode 100644
index 00000000..44acec70
--- /dev/null
+++ b/lib/libalpm/dload.c
@@ -0,0 +1,463 @@
+/*
+ * download.c
+ *
+ * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+/* the following two are needed on BSD for libfetch */
+#if defined(HAVE_SYS_SYSLIMITS_H)
+#include <sys/syslimits.h> /* PATH_MAX */
+#endif
+#if defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#endif
+
+#if defined(HAVE_LIBDOWNLOAD)
+#include <download.h>
+#elif defined(HAVE_LIBFETCH)
+#include <fetch.h>
+#define downloadFreeURL fetchFreeURL
+#define downloadLastErrCode fetchLastErrCode
+#define downloadLastErrString fetchLastErrString
+#define downloadParseURL fetchParseURL
+#define downloadTimeout fetchTimeout
+#define downloadXGet fetchXGet
+#endif
+
+/* libalpm */
+#include "dload.h"
+#include "alpm_list.h"
+#include "alpm.h"
+#include "log.h"
+#include "util.h"
+#include "handle.h"
+
+static char *get_filename(const char *url) {
+ char *filename = strrchr(url, '/');
+ if(filename != NULL) {
+ filename++;
+ }
+ return(filename);
+}
+
+static char *get_destfile(const char *path, const char *filename) {
+ char *destfile;
+ /* len = localpath len + filename len + null */
+ int len = strlen(path) + strlen(filename) + 1;
+ CALLOC(destfile, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL));
+ snprintf(destfile, len, "%s%s", path, filename);
+
+ return(destfile);
+}
+
+static char *get_tempfile(const char *path, const char *filename) {
+ char *tempfile;
+ /* len = localpath len + filename len + '.part' len + null */
+ int len = strlen(path) + strlen(filename) + 6;
+ CALLOC(tempfile, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL));
+ snprintf(tempfile, len, "%s%s.part", path, filename);
+
+ return(tempfile);
+}
+
+#if defined(INTERNAL_DOWNLOAD)
+/* Build a 'struct url' from an url. */
+static struct url *url_for_string(const char *url)
+{
+ struct url *ret = NULL;
+ ret = downloadParseURL(url);
+ if(!ret) {
+ _alpm_log(PM_LOG_ERROR, _("url '%s' is invalid\n"), url);
+ RET_ERR(PM_ERR_SERVER_BAD_URL, NULL);
+ }
+
+ /* if no URL scheme specified, assume HTTP */
+ if(strlen(ret->scheme) == 0) {
+ _alpm_log(PM_LOG_WARNING, _("url scheme not specified, assuming HTTP\n"));
+ strcpy(ret->scheme, SCHEME_HTTP);
+ }
+ /* add a user & password for anonymous FTP */
+ if(strcmp(ret->scheme,SCHEME_FTP) == 0 && strlen(ret->user) == 0) {
+ strcpy(ret->user, "anonymous");
+ strcpy(ret->pwd, "libalpm@guest");
+ }
+
+ return(ret);
+}
+
+static int download_internal(const char *url, const char *localpath,
+ time_t mtimeold, time_t *mtimenew) {
+ FILE *dlf, *localf = NULL;
+ struct url_stat ust;
+ struct stat st;
+ int chk_resume = 0;
+ int dl_thisfile = 0;
+ char *tempfile, *destfile, *filename;
+ int ret = 0;
+ struct url *fileurl = url_for_string(url);
+
+ if(!fileurl) {
+ return(-1);
+ }
+
+ filename = get_filename(url);
+ if(!filename) {
+ return(-1);
+ }
+ destfile = get_destfile(localpath, filename);
+ tempfile = get_tempfile(localpath, filename);
+
+ /* pass the raw filename for passing to the callback function */
+ _alpm_log(PM_LOG_DEBUG, "using '%s' for download progress\n", filename);
+
+ if(stat(tempfile, &st) == 0 && st.st_size > 0) {
+ _alpm_log(PM_LOG_DEBUG, "existing file found, using it\n");
+ fileurl->offset = (off_t)st.st_size;
+ dl_thisfile = st.st_size;
+ localf = fopen(tempfile, "ab");
+ chk_resume = 1;
+ } else {
+ fileurl->offset = (off_t)0;
+ dl_thisfile = 0;
+ }
+
+ /* libdownload does not reset the error code, reset it in
+ * the case of previous errors */
+ downloadLastErrCode = 0;
+
+ /* 10s timeout - TODO make a config option */
+ downloadTimeout = 10000;
+
+ dlf = downloadXGet(fileurl, &ust, (handle->nopassiveftp ? "" : "p"));
+
+ if(downloadLastErrCode != 0 || dlf == NULL) {
+ const char *host = _("disk");
+ if(strcmp(SCHEME_FILE, fileurl->scheme) != 0) {
+ host = fileurl->host;
+ }
+ pm_errno = PM_ERR_LIBDOWNLOAD;
+ _alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"),
+ filename, host, downloadLastErrString);
+ ret = -1;
+ goto cleanup;
+ } else {
+ _alpm_log(PM_LOG_DEBUG, "connected to %s successfully\n", fileurl->host);
+ }
+
+ if(ust.mtime && mtimeold && ust.mtime == mtimeold) {
+ _alpm_log(PM_LOG_DEBUG, "mtimes are identical, skipping %s\n", filename);
+ ret = 1;
+ goto cleanup;
+ }
+
+ if(ust.mtime && mtimenew) {
+ *mtimenew = ust.mtime;
+ }
+
+ if(chk_resume && fileurl->offset == 0) {
+ _alpm_log(PM_LOG_WARNING, _("cannot resume download, starting over\n"));
+ if(localf != NULL) {
+ fclose(localf);
+ localf = NULL;
+ }
+ }
+
+ if(localf == NULL) {
+ _alpm_rmrf(tempfile);
+ fileurl->offset = (off_t)0;
+ dl_thisfile = 0;
+ localf = fopen(tempfile, "wb");
+ if(localf == NULL) { /* still null? */
+ _alpm_log(PM_LOG_ERROR, _("cannot write to file '%s'\n"), tempfile);
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ /* Progress 0 - initialize */
+ if(handle->dlcb) {
+ handle->dlcb(filename, 0, ust.size);
+ }
+
+ int nread = 0;
+ char buffer[PM_DLBUF_LEN];
+ while((nread = fread(buffer, 1, PM_DLBUF_LEN, dlf)) > 0) {
+ if(ferror(dlf)) {
+ pm_errno = PM_ERR_LIBDOWNLOAD;
+ _alpm_log(PM_LOG_ERROR, _("error downloading '%s': %s\n"),
+ filename, downloadLastErrString);
+ ret = -1;
+ goto cleanup;
+ }
+
+ int nwritten = 0;
+ while(nwritten < nread) {
+ nwritten += fwrite(buffer, 1, (nread - nwritten), localf);
+ if(ferror(localf)) {
+ _alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"),
+ destfile, strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+ }
+ dl_thisfile += nread;
+
+ if(handle->dlcb) {
+ handle->dlcb(filename, dl_thisfile, ust.size);
+ }
+ }
+ /* probably safer to close the file descriptors now before renaming the file,
+ * for example to make sure the buffers are flushed.
+ */
+ fclose(localf);
+ localf = NULL;
+ fclose(dlf);
+ dlf = NULL;
+
+ rename(tempfile, destfile);
+ ret = 0;
+
+cleanup:
+ FREE(tempfile);
+ FREE(destfile);
+ if(localf != NULL) {
+ fclose(localf);
+ }
+ if(dlf != NULL) {
+ fclose(dlf);
+ }
+ downloadFreeURL(fileurl);
+ return(ret);
+}
+#endif
+
+static int download_external(const char *url, const char *localpath,
+ time_t mtimeold, time_t *mtimenew) {
+ int ret = 0;
+ int retval;
+ int usepart = 0;
+ char *ptr1, *ptr2;
+ char origCmd[PATH_MAX];
+ char parsedCmd[PATH_MAX] = "";
+ char cwd[PATH_MAX];
+ char *destfile, *tempfile, *filename;
+
+ if(!handle->xfercommand) {
+ RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
+ }
+
+ filename = get_filename(url);
+ if(!filename) {
+ RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
+ }
+ destfile = get_destfile(localpath, filename);
+ tempfile = get_tempfile(localpath, filename);
+
+ /* replace all occurrences of %o with fn.part */
+ strncpy(origCmd, handle->xfercommand, sizeof(origCmd));
+ ptr1 = origCmd;
+ while((ptr2 = strstr(ptr1, "%o"))) {
+ usepart = 1;
+ ptr2[0] = '\0';
+ strcat(parsedCmd, ptr1);
+ strcat(parsedCmd, tempfile);
+ ptr1 = ptr2 + 2;
+ }
+ strcat(parsedCmd, ptr1);
+ /* replace all occurrences of %u with the download URL */
+ strncpy(origCmd, parsedCmd, sizeof(origCmd));
+ parsedCmd[0] = '\0';
+ ptr1 = origCmd;
+ while((ptr2 = strstr(ptr1, "%u"))) {
+ ptr2[0] = '\0';
+ strcat(parsedCmd, ptr1);
+ strcat(parsedCmd, url);
+ ptr1 = ptr2 + 2;
+ }
+ strcat(parsedCmd, ptr1);
+ /* cwd to the download directory */
+ getcwd(cwd, PATH_MAX);
+ if(chdir(localpath)) {
+ _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), localpath);
+ pm_errno = PM_ERR_EXTERNAL_DOWNLOAD;
+ ret = -1;
+ goto cleanup;
+ }
+ /* execute the parsed command via /bin/sh -c */
+ _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd);
+ retval = system(parsedCmd);
+
+ if(retval == -1) {
+ _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!\n"));
+ pm_errno = PM_ERR_EXTERNAL_DOWNLOAD;
+ ret = -1;
+ } else if(retval != 0) {
+ /* download failed */
+ _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
+ "code (%d)\n", retval);
+ ret = -1;
+ } else {
+ /* download was successful */
+ if(usepart) {
+ rename(tempfile, destfile);
+ }
+ ret = 0;
+ }
+
+cleanup:
+ chdir(cwd);
+ if(ret == -1) {
+ /* hack to let an user the time to cancel a download */
+ sleep(2);
+ }
+ FREE(destfile);
+ FREE(tempfile);
+
+ return(ret);
+}
+
+static int download(const char *url, const char *localpath,
+ time_t mtimeold, time_t *mtimenew) {
+ int ret;
+ const char *proto = "file://";
+ int len = strlen(proto);
+ if(strncmp(url, proto, len) == 0) {
+ /* we can simply grab an absolute path from the file:// url by starting
+ * our path at the char following the proto (the root '/')
+ */
+ const char *sourcefile = url + len;
+ const char *filename = get_filename(url);
+ char *destfile = get_destfile(localpath, filename);
+
+ ret = _alpm_copyfile(sourcefile, destfile);
+ FREE(destfile);
+ /* copyfile returns 1 on failure, we want to return -1 on failure */
+ return(ret ? -1 : 0);
+ }
+
+ /* We have a few things to take into account here.
+ * 1. If we have both internal/external available, choose based on
+ * whether xfercommand is populated.
+ * 2. If we only have external available, we should first check
+ * if a command was provided before we drop into download_external.
+ */
+ if(handle->xfercommand == NULL) {
+#if defined(INTERNAL_DOWNLOAD)
+ ret = download_internal(url, localpath, mtimeold, mtimenew);
+#else
+ RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
+#endif
+ } else {
+ ret = download_external(url, localpath, mtimeold, mtimenew);
+ }
+ return(ret);
+}
+
+/*
+ * Download a single file
+ * - if mtimeold is non-NULL, then only download the file if it's different
+ * than mtimeold.
+ * - if *mtimenew is non-NULL, it will be filled with the mtime of the remote
+ * file.
+ *
+ * RETURN: 0 for successful download
+ * 1 if the mtimes are identical
+ * -1 on error
+ */
+int _alpm_download_single_file(const char *filename,
+ alpm_list_t *servers, const char *localpath,
+ time_t mtimeold, time_t *mtimenew)
+{
+ alpm_list_t *i;
+ int ret = -1;
+
+ for(i = servers; i; i = i->next) {
+ const char *server = i->data;
+ char *fileurl = NULL;
+ int len;
+
+ /* print server + filename into a buffer */
+ len = strlen(server) + strlen(filename) + 2;
+ CALLOC(fileurl, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1));
+ snprintf(fileurl, len, "%s/%s", server, filename);
+
+ ret = download(fileurl, localpath, mtimeold, mtimenew);
+ FREE(fileurl);
+ if(ret != -1) {
+ break;
+ }
+ }
+
+ return(ret);
+}
+
+int _alpm_download_files(alpm_list_t *files,
+ alpm_list_t *servers, const char *localpath)
+{
+ int ret = 0;
+ alpm_list_t *lp;
+
+ for(lp = files; lp; lp = lp->next) {
+ char *filename = lp->data;
+ if(_alpm_download_single_file(filename, servers,
+ localpath, 0, NULL) == -1) {
+ ret++;
+ }
+ }
+
+ return(ret);
+}
+
+/** Fetch a remote pkg.
+ * @param url URL of the package to download
+ * @return the downloaded filepath on success, NULL on error
+ * @addtogroup alpm_misc
+ */
+char SYMEXPORT *alpm_fetch_pkgurl(const char *url)
+{
+ char *filename, *filepath;
+ const char *cachedir;
+ int ret;
+
+ ALPM_LOG_FUNC;
+
+ filename = get_filename(url);
+
+ /* find a valid cache dir to download to */
+ cachedir = _alpm_filecache_setup();
+
+ /* download the file */
+ ret = download(url, cachedir, 0, NULL);
+ if(ret == -1) {
+ _alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url);
+ return(NULL);
+ }
+ _alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", url);
+
+ /* we should be able to find the file the second time around */
+ filepath = _alpm_filecache_find(filename);
+ return(filepath);
+}
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/error.h b/lib/libalpm/dload.h
index e417195f..eb642522 100644
--- a/lib/libalpm/error.h
+++ b/lib/libalpm/dload.h
@@ -1,7 +1,7 @@
/*
- * error.h
+ * dload.h
*
- * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
+ * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,13 +16,23 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _ALPM_ERROR_H
-#define _ALPM_ERROR_H
+#ifndef _ALPM_DLOAD_H
+#define _ALPM_DLOAD_H
-#define RET_ERR(err, ret) do { pm_errno = (err); \
- _alpm_log(PM_LOG_DEBUG, "returning error %d from %s : %s\n", err, __func__, alpm_strerrorlast()); \
- return(ret); } while(0)
+#include "alpm_list.h"
+#include "alpm.h"
-#endif /* _ALPM_ERROR_H */
+#include <time.h>
+
+#define PM_DLBUF_LEN (1024 * 10)
+
+int _alpm_download_single_file(const char *filename,
+ alpm_list_t *servers, const char *localpath,
+ time_t mtimeold, time_t *mtimenew);
+
+int _alpm_download_files(alpm_list_t *files,
+ alpm_list_t *servers, const char *localpath);
+
+#endif /* _ALPM_DLOAD_H */
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index a68340ad..05caf8ec 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -1,10 +1,7 @@
/*
* error.c
*
- * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
- * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
- * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
- * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
+ * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,12 +19,28 @@
#include "config.h"
+/* TODO: needed for the libfetch stuff, unfortunately- we should kill it */
+#include <stdio.h>
+#include <limits.h>
+/* the following two are needed on BSD for libfetch */
+#if defined(HAVE_SYS_SYSLIMITS_H)
+#include <sys/syslimits.h> /* PATH_MAX */
+#endif
+#if defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#endif
+
+#if defined(HAVE_LIBDOWNLOAD)
+#include <download.h> /* downloadLastErrString */
+#elif defined(HAVE_LIBFETCH)
+#include <fetch.h> /* fetchLastErrString */
+#define downloadLastErrString fetchLastErrString
+#endif
+
/* libalpm */
-#include "error.h"
#include "util.h"
#include "alpm.h"
-/* TODO does this really need a file all on its own? */
const char SYMEXPORT *alpm_strerrorlast(void)
{
return alpm_strerror(pm_errno);
@@ -74,13 +87,6 @@ const char SYMEXPORT *alpm_strerror(int err)
/* Servers */
case PM_ERR_SERVER_BAD_URL:
return _("invalid url for server");
- /* Configuration */
- case PM_ERR_OPT_LOGFILE:
- case PM_ERR_OPT_DBPATH:
- case PM_ERR_OPT_LOCALDB:
- case PM_ERR_OPT_SYNCDB:
- case PM_ERR_OPT_USESYSLOG:
- return _("could not set parameter");
/* Transactions */
case PM_ERR_TRANS_NOT_NULL:
return _("transaction already initialized");
@@ -109,21 +115,17 @@ const char SYMEXPORT *alpm_strerror(int err)
return _("cannot open package file");
case PM_ERR_PKG_LOAD:
return _("cannot load package data");
- case PM_ERR_PKG_INSTALLED:
- return _("package already installed");
case PM_ERR_PKG_CANT_FRESH:
return _("package not installed or lesser version");
case PM_ERR_PKG_CANT_REMOVE:
return _("cannot remove all files for package");
case PM_ERR_PKG_INVALID_NAME:
- return _("package name is not valid");
- case PM_ERR_PKG_CORRUPTED:
- return _("corrupted package");
+ return _("package filename is not valid");
case PM_ERR_PKG_REPO_NOT_FOUND:
return _("no such repository");
/* Deltas */
- case PM_ERR_DLT_CORRUPTED:
- return _("corrupted delta");
+ case PM_ERR_DLT_INVALID:
+ return _("invalid or corrupted delta");
case PM_ERR_DLT_PATCHFAILED:
return _("delta patch failed");
/* Groups */
@@ -141,16 +143,26 @@ const char SYMEXPORT *alpm_strerror(int err)
return _("user aborted the operation");
case PM_ERR_INTERNAL_ERROR:
return _("internal error");
- case PM_ERR_LIBARCHIVE_ERROR:
- return _("libarchive error");
case PM_ERR_PKG_HOLD:
/* TODO wow this is not descriptive at all... what does this mean? */
return _("not confirmed");
case PM_ERR_INVALID_REGEX:
return _("invalid regular expression");
- /* Downloading */
- case PM_ERR_CONNECT_FAILED:
- return _("connection to remote host failed");
+ /* Errors from external libraries- our own wrapper error */
+ case PM_ERR_LIBARCHIVE:
+ /* it would be nice to use archive_error_string() here, but that
+ * requires the archive struct, so we can't. Just use a generic
+ * error string instead. */
+ return _("libarchive error");
+ case PM_ERR_LIBDOWNLOAD:
+#if defined(INTERNAL_DOWNLOAD)
+ return downloadLastErrString;
+#else
+ /* obviously shouldn't get here... */
+ return _("download library error");
+#endif
+ case PM_ERR_EXTERNAL_DOWNLOAD:
+ return _("error invoking external downloader");
/* Unknown error! */
default:
return _("unexpected error");
diff --git a/lib/libalpm/graph.h b/lib/libalpm/graph.h
new file mode 100644
index 00000000..3078e25f
--- /dev/null
+++ b/lib/libalpm/graph.h
@@ -0,0 +1,56 @@
+/*
+ * graph.h - helpful graph structure and setup/teardown methods
+ *
+ * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "alpm_list.h"
+#include "util.h" /* MALLOC() */
+#include "alpm.h"
+
+struct __pmgraph_t {
+ char state; /* 0: untouched, -1: entered, other: leaving time */
+ void *data;
+ unsigned long int weight; /* weight of the node */
+ struct __pmgraph_t *parent; /* where did we come from? */
+ alpm_list_t *children;
+ alpm_list_t *childptr; /* points to a child in children list */
+};
+typedef struct __pmgraph_t pmgraph_t;
+
+static pmgraph_t *_alpm_graph_new(void)
+{
+ pmgraph_t *graph = NULL;
+
+ MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL));
+
+ if(graph) {
+ graph->state = 0;
+ graph->data = NULL;
+ graph->parent = NULL;
+ graph->children = NULL;
+ graph->childptr = NULL;
+ }
+ return(graph);
+}
+
+static void _alpm_graph_free(void *data)
+{
+ pmgraph_t *graph = data;
+ alpm_list_free(graph->children);
+ free(graph);
+}
+
diff --git a/lib/libalpm/group.c b/lib/libalpm/group.c
index 050bcbd5..3e080a58 100644
--- a/lib/libalpm/group.c
+++ b/lib/libalpm/group.c
@@ -27,17 +27,17 @@
#include "group.h"
#include "alpm_list.h"
#include "util.h"
-#include "error.h"
#include "log.h"
#include "alpm.h"
-pmgrp_t *_alpm_grp_new()
+pmgrp_t *_alpm_grp_new(const char *name)
{
pmgrp_t* grp;
ALPM_LOG_FUNC;
CALLOC(grp, 1, sizeof(pmgrp_t), RET_ERR(PM_ERR_MEMORY, NULL));
+ STRDUP(grp->name, name, RET_ERR(PM_ERR_MEMORY, NULL));
return(grp);
}
@@ -50,20 +50,12 @@ void _alpm_grp_free(pmgrp_t *grp)
return;
}
- FREELIST(grp->packages);
+ FREE(grp->name);
+ /* do NOT free the contents of the list, just the nodes */
+ alpm_list_free(grp->packages);
FREE(grp);
}
-/* Helper function for sorting groups
- */
-int _alpm_grp_cmp(const void *g1, const void *g2)
-{
- pmgrp_t *grp1 = (pmgrp_t *)g1;
- pmgrp_t *grp2 = (pmgrp_t *)g2;
-
- return(strcmp(grp1->name, grp2->name));
-}
-
const char SYMEXPORT *alpm_grp_get_name(const pmgrp_t *grp)
{
ALPM_LOG_FUNC;
@@ -74,7 +66,7 @@ const char SYMEXPORT *alpm_grp_get_name(const pmgrp_t *grp)
return grp->name;
}
-const alpm_list_t SYMEXPORT *alpm_grp_get_pkgs(const pmgrp_t *grp)
+alpm_list_t SYMEXPORT *alpm_grp_get_pkgs(const pmgrp_t *grp)
{
ALPM_LOG_FUNC;
diff --git a/lib/libalpm/group.h b/lib/libalpm/group.h
index 88fc8b32..e261260c 100644
--- a/lib/libalpm/group.h
+++ b/lib/libalpm/group.h
@@ -19,19 +19,17 @@
#ifndef _ALPM_GROUP_H
#define _ALPM_GROUP_H
-/* Groups */
-#define GRP_NAME_LEN 256
-
#include "alpm.h"
struct __pmgrp_t {
- char name[GRP_NAME_LEN];
- alpm_list_t *packages; /* List of strings */
+ /** group name */
+ char *name;
+ /** list of pmpkg_t packages */
+ alpm_list_t *packages;
};
-pmgrp_t *_alpm_grp_new(void);
+pmgrp_t *_alpm_grp_new(const char *name);
void _alpm_grp_free(pmgrp_t *grp);
-int _alpm_grp_cmp(const void *g1, const void *g2);
#endif /* _ALPM_GROUP_H */
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 36822285..c01dd551 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -23,7 +23,6 @@
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <syslog.h>
@@ -36,10 +35,8 @@
#include "alpm_list.h"
#include "util.h"
#include "log.h"
-#include "error.h"
#include "trans.h"
#include "alpm.h"
-#include "server.h"
/* global var for handle (private to libalpm) */
pmhandle_t *handle = NULL;
@@ -55,8 +52,6 @@ pmhandle_t *_alpm_handle_new()
handle->lckfd = -1;
handle->logstream = NULL;
- /* see if we're root or not */
- handle->uid = geteuid();
handle->root = NULL;
handle->dbpath = NULL;
handle->cachedirs = NULL;
@@ -386,7 +381,7 @@ void SYMEXPORT alpm_option_set_cachedirs(alpm_list_t *cachedirs)
int SYMEXPORT alpm_option_remove_cachedir(const char *cachedir)
{
- void *vdata = NULL;
+ char *vdata = NULL;
char *newcachedir;
size_t cachedirlen;
/* verify cachedir ends in a '/' */
@@ -397,8 +392,7 @@ int SYMEXPORT alpm_option_remove_cachedir(const char *cachedir)
newcachedir = calloc(cachedirlen + 1, sizeof(char));
strncpy(newcachedir, cachedir, cachedirlen);
newcachedir[cachedirlen-1] = '/';
- handle->cachedirs = alpm_list_remove(handle->cachedirs, newcachedir,
- _alpm_str_cmp, &vdata);
+ handle->cachedirs = alpm_list_remove_str(handle->cachedirs, newcachedir, &vdata);
FREE(newcachedir);
if(vdata != NULL) {
FREE(vdata);
@@ -451,9 +445,8 @@ void SYMEXPORT alpm_option_set_noupgrades(alpm_list_t *noupgrade)
int SYMEXPORT alpm_option_remove_noupgrade(const char *pkg)
{
- void *vdata = NULL;
- handle->noupgrade = alpm_list_remove(handle->noupgrade, pkg,
- _alpm_str_cmp, &vdata);
+ char *vdata = NULL;
+ handle->noupgrade = alpm_list_remove_str(handle->noupgrade, pkg, &vdata);
if(vdata != NULL) {
FREE(vdata);
return(1);
@@ -474,9 +467,8 @@ void SYMEXPORT alpm_option_set_noextracts(alpm_list_t *noextract)
int SYMEXPORT alpm_option_remove_noextract(const char *pkg)
{
- void *vdata = NULL;
- handle->noextract = alpm_list_remove(handle->noextract, pkg,
- _alpm_str_cmp, &vdata);
+ char *vdata = NULL;
+ handle->noextract = alpm_list_remove_str(handle->noextract, pkg, &vdata);
if(vdata != NULL) {
FREE(vdata);
return(1);
@@ -497,9 +489,8 @@ void SYMEXPORT alpm_option_set_ignorepkgs(alpm_list_t *ignorepkgs)
int SYMEXPORT alpm_option_remove_ignorepkg(const char *pkg)
{
- void *vdata = NULL;
- handle->ignorepkg = alpm_list_remove(handle->ignorepkg, pkg,
- _alpm_str_cmp, &vdata);
+ char *vdata = NULL;
+ handle->ignorepkg = alpm_list_remove_str(handle->ignorepkg, pkg, &vdata);
if(vdata != NULL) {
FREE(vdata);
return(1);
@@ -520,9 +511,8 @@ void SYMEXPORT alpm_option_set_holdpkgs(alpm_list_t *holdpkgs)
int SYMEXPORT alpm_option_remove_holdpkg(const char *pkg)
{
- void *vdata = NULL;
- handle->holdpkg = alpm_list_remove(handle->holdpkg, pkg,
- _alpm_str_cmp, &vdata);
+ char *vdata = NULL;
+ handle->holdpkg = alpm_list_remove_str(handle->holdpkg, pkg, &vdata);
if(vdata != NULL) {
FREE(vdata);
return(1);
@@ -543,9 +533,8 @@ void SYMEXPORT alpm_option_set_ignoregrps(alpm_list_t *ignoregrps)
int SYMEXPORT alpm_option_remove_ignoregrp(const char *grp)
{
- void *vdata = NULL;
- handle->ignoregrp = alpm_list_remove(handle->ignoregrp, grp,
- _alpm_str_cmp, &vdata);
+ char *vdata = NULL;
+ handle->ignoregrp = alpm_list_remove_str(handle->ignoregrp, grp, &vdata);
if(vdata != NULL) {
FREE(vdata);
return(1);
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 5051917e..9c537b14 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -30,7 +30,6 @@
typedef struct _pmhandle_t {
/* internal usage */
- uid_t uid; /* current UID */ /* TODO is this used? */
pmdb_t *db_local; /* local db pointer */
alpm_list_t *dbs_sync; /* List of (pmdb_t *) */
FILE *logstream; /* log file stream pointer */
@@ -50,7 +49,7 @@ typedef struct _pmhandle_t {
/* package lists */
alpm_list_t *noupgrade; /* List of packages NOT to be upgraded */
- alpm_list_t *noextract; /* List of packages NOT to extract */ /*TODO is this used?*/
+ alpm_list_t *noextract; /* List of files NOT to extract */
alpm_list_t *ignorepkg; /* List of packages to ignore */
alpm_list_t *holdpkg; /* List of packages which 'hold' pacman */
alpm_list_t *ignoregrp; /* List of groups to ignore */
diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c
index 4445f935..3ba5042c 100644
--- a/lib/libalpm/log.c
+++ b/lib/libalpm/log.c
@@ -30,7 +30,6 @@
#include "log.h"
#include "handle.h"
#include "util.h"
-#include "error.h"
#include "alpm.h"
/** \addtogroup alpm_log Logging Functions
diff --git a/lib/libalpm/md5.c b/lib/libalpm/md5.c
index 4c903895..1923242a 100644
--- a/lib/libalpm/md5.c
+++ b/lib/libalpm/md5.c
@@ -3,14 +3,15 @@
*
* Copyright (C) 2006-2007 Christophe Devine
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License, version 2.1 as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
@@ -25,8 +26,9 @@
* Pacman Notes:
*
* Taken from the XySSL project at www.xyssl.org under terms of the
- * LGPL. This is from version 0.7 of the library, and has been modified
+ * GPL. This is from version 0.9 of the library, and has been modified
* as following, which may be helpful for future updates:
+ * * remove "xyssl/config.h" include
* * change include from "xyssl/md5.h" to "md5.h"
* * removal of HMAC code
* * removal of SELF_TEST code
@@ -35,12 +37,9 @@
* int md5_file( char *path, unsigned char *output )
* to
* int md5_file( const char *path, unsigned char *output )
+ * * various static/inline changes
*/
-#ifndef _CRT_SECURE_NO_DEPRECATE
-#define _CRT_SECURE_NO_DEPRECATE 1
-#endif
-
#include <string.h>
#include <stdio.h>
@@ -49,8 +48,8 @@
/*
* 32-bit integer manipulation macros (little endian)
*/
-#ifndef GET_UINT32_LE
-#define GET_UINT32_LE(n,b,i) \
+#ifndef GET_ULONG_LE
+#define GET_ULONG_LE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] ) \
| ( (unsigned long) (b)[(i) + 1] << 8 ) \
@@ -59,8 +58,8 @@
}
#endif
-#ifndef PUT_UINT32_LE
-#define PUT_UINT32_LE(n,b,i) \
+#ifndef PUT_ULONG_LE
+#define PUT_ULONG_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
@@ -87,22 +86,22 @@ static inline void md5_process( md5_context *ctx, unsigned char data[64] )
{
unsigned long X[16], A, B, C, D;
- GET_UINT32_LE( X[ 0], data, 0 );
- GET_UINT32_LE( X[ 1], data, 4 );
- GET_UINT32_LE( X[ 2], data, 8 );
- GET_UINT32_LE( X[ 3], data, 12 );
- GET_UINT32_LE( X[ 4], data, 16 );
- GET_UINT32_LE( X[ 5], data, 20 );
- GET_UINT32_LE( X[ 6], data, 24 );
- GET_UINT32_LE( X[ 7], data, 28 );
- GET_UINT32_LE( X[ 8], data, 32 );
- GET_UINT32_LE( X[ 9], data, 36 );
- GET_UINT32_LE( X[10], data, 40 );
- GET_UINT32_LE( X[11], data, 44 );
- GET_UINT32_LE( X[12], data, 48 );
- GET_UINT32_LE( X[13], data, 52 );
- GET_UINT32_LE( X[14], data, 56 );
- GET_UINT32_LE( X[15], data, 60 );
+ GET_ULONG_LE( X[ 0], data, 0 );
+ GET_ULONG_LE( X[ 1], data, 4 );
+ GET_ULONG_LE( X[ 2], data, 8 );
+ GET_ULONG_LE( X[ 3], data, 12 );
+ GET_ULONG_LE( X[ 4], data, 16 );
+ GET_ULONG_LE( X[ 5], data, 20 );
+ GET_ULONG_LE( X[ 6], data, 24 );
+ GET_ULONG_LE( X[ 7], data, 28 );
+ GET_ULONG_LE( X[ 8], data, 32 );
+ GET_ULONG_LE( X[ 9], data, 36 );
+ GET_ULONG_LE( X[10], data, 40 );
+ GET_ULONG_LE( X[11], data, 44 );
+ GET_ULONG_LE( X[12], data, 48 );
+ GET_ULONG_LE( X[13], data, 52 );
+ GET_ULONG_LE( X[14], data, 56 );
+ GET_ULONG_LE( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
@@ -250,7 +249,7 @@ static inline void md5_update( md5_context *ctx, unsigned char *input, int ilen
}
}
-static unsigned char md5_padding[64] =
+static const unsigned char md5_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -261,7 +260,7 @@ static unsigned char md5_padding[64] =
/*
* MD5 final digest
*/
-static inline void md5_finish( md5_context *ctx, unsigned char *output )
+static inline void md5_finish( md5_context *ctx, unsigned char output[16] )
{
unsigned long last, padn;
unsigned long high, low;
@@ -271,8 +270,8 @@ static inline void md5_finish( md5_context *ctx, unsigned char *output )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
- PUT_UINT32_LE( low, msglen, 0 );
- PUT_UINT32_LE( high, msglen, 4 );
+ PUT_ULONG_LE( low, msglen, 0 );
+ PUT_ULONG_LE( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
@@ -280,17 +279,16 @@ static inline void md5_finish( md5_context *ctx, unsigned char *output )
md5_update( ctx, (unsigned char *) md5_padding, padn );
md5_update( ctx, msglen, 8 );
- PUT_UINT32_LE( ctx->state[0], output, 0 );
- PUT_UINT32_LE( ctx->state[1], output, 4 );
- PUT_UINT32_LE( ctx->state[2], output, 8 );
- PUT_UINT32_LE( ctx->state[3], output, 12 );
+ PUT_ULONG_LE( ctx->state[0], output, 0 );
+ PUT_ULONG_LE( ctx->state[1], output, 4 );
+ PUT_ULONG_LE( ctx->state[2], output, 8 );
+ PUT_ULONG_LE( ctx->state[3], output, 12 );
}
/*
- * Output = MD5( input buffer )
+ * output = MD5( input buffer )
*/
-void md5( unsigned char *input, int ilen,
- unsigned char *output )
+void md5( unsigned char *input, int ilen, unsigned char output[16] )
{
md5_context ctx;
@@ -302,9 +300,9 @@ void md5( unsigned char *input, int ilen,
}
/*
- * Output = MD5( file contents )
+ * output = MD5( file contents )
*/
-int md5_file( const char *path, unsigned char *output )
+int md5_file( const char *path, unsigned char output[16] )
{
FILE *f;
size_t n;
diff --git a/lib/libalpm/md5.h b/lib/libalpm/md5.h
index d206e463..25b4ff58 100644
--- a/lib/libalpm/md5.h
+++ b/lib/libalpm/md5.h
@@ -3,14 +3,15 @@
*
* Copyright (C) 2006-2007 Christophe Devine
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License, version 2.1 as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
@@ -20,12 +21,7 @@
#ifndef _MD5_H
#define _MD5_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
- * \internal
* \brief MD5 context structure
*/
typedef struct
@@ -37,18 +33,15 @@ typedef struct
md5_context;
/**
- * \internal
* \brief Output = MD5( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output MD5 checksum result
*/
-void md5( unsigned char *input, int ilen,
- unsigned char *output );
+void md5( unsigned char *input, int ilen, unsigned char output[16] );
/**
- * \internal
* \brief Output = MD5( file contents )
*
* \param path input file name
@@ -57,10 +50,6 @@ void md5( unsigned char *input, int ilen,
* \return 0 if successful, 1 if fopen failed,
* or 2 if fread failed
*/
-int md5_file( const char *path, unsigned char *output );
-
-#ifdef __cplusplus
-}
-#endif
+int md5_file( const char *path, unsigned char output[16] );
#endif /* md5.h */
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index 794a2f7d..07b5fa38 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -31,7 +31,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <locale.h> /* setlocale */
/* libarchive */
#include <archive.h>
@@ -42,7 +41,6 @@
#include "alpm_list.h"
#include "log.h"
#include "util.h"
-#include "error.h"
#include "db.h"
#include "cache.h"
#include "delta.h"
@@ -54,42 +52,13 @@
* @{
*/
-/** Create a package from a file.
- * If full is false, the archive is read only until all necessary
- * metadata is found. If it is true, the entire archive is read, which
- * serves as a verfication of integrity and the filelist can be created.
- * @param filename location of the package tarball
- * @param full whether to stop the load after metadata is read or continue
- * through the full archive
- * @param pkg address of the package pointer
- * @return 0 on success, -1 on error (pm_errno is set accordingly)
- */
-int SYMEXPORT alpm_pkg_load(const char *filename, unsigned short full,
- pmpkg_t **pkg)
-{
- _alpm_log(PM_LOG_FUNCTION, "enter alpm_pkg_load\n");
-
- /* Sanity checks */
- ASSERT(filename != NULL && strlen(filename) != 0,
- RET_ERR(PM_ERR_WRONG_ARGS, -1));
- ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
-
- *pkg = _alpm_pkg_load(filename, full);
- if(*pkg == NULL) {
- /* pm_errno is set by pkg_load */
- return(-1);
- }
-
- return(0);
-}
-
/** Free a package.
* @param pkg package pointer to free
* @return 0 on success, -1 on error (pm_errno is set accordingly)
*/
int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)
{
- _alpm_log(PM_LOG_FUNCTION, "enter alpm_pkg_free\n");
+ ALPM_LOG_FUNC;
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
@@ -108,8 +77,7 @@ int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)
int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
{
char *fpath;
- char *md5sum = NULL;
- int retval = 0;
+ int retval;
ALPM_LOG_FUNC;
@@ -119,44 +87,19 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1));
fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg));
- md5sum = alpm_get_md5sum(fpath);
- if(md5sum == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not get md5sum for package %s-%s\n"),
- alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
- pm_errno = PM_ERR_NOT_A_FILE;
+ retval = _alpm_test_md5sum(fpath, alpm_pkg_get_md5sum(pkg));
+
+ if(retval == 0) {
+ return(0);
+ } else if (retval == 1) {
+ pm_errno = PM_ERR_PKG_INVALID;
retval = -1;
- } else {
- if(strcmp(md5sum, alpm_pkg_get_md5sum(pkg)) == 0) {
- _alpm_log(PM_LOG_DEBUG, "md5sums for package %s-%s match\n",
- alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
- } else {
- _alpm_log(PM_LOG_ERROR, _("md5sums do not match for package %s-%s\n"),
- alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
- pm_errno = PM_ERR_PKG_INVALID;
- retval = -1;
- }
}
- FREE(fpath);
- FREE(md5sum);
-
return(retval);
}
-/** Compare versions.
- * @param ver1 first version
- * @param ver2 secont version
- * @return postive, 0 or negative if ver1 is less, equal or more
- * than ver2, respectively.
- */
-int SYMEXPORT alpm_pkg_vercmp(const char *ver1, const char *ver2)
-{
- ALPM_LOG_FUNC;
-
- return(_alpm_versioncmp(ver1, ver2));
-}
-
const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)
{
ALPM_LOG_FUNC;
@@ -169,45 +112,18 @@ const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)
_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
}
- if(!strlen(pkg->filename)) {
- /* construct the file name, it's not in the desc file */
- if(pkg->arch && strlen(pkg->arch) > 0) {
- snprintf(pkg->filename, PKG_FILENAME_LEN, "%s-%s-%s" PKGEXT,
- pkg->name, pkg->version, pkg->arch);
- } else {
- snprintf(pkg->filename, PKG_FILENAME_LEN, "%s-%s" PKGEXT,
- pkg->name, pkg->version);
- }
- }
-
return pkg->filename;
}
const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
- }
return pkg->name;
}
const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
- }
return pkg->version;
}
@@ -523,7 +439,7 @@ void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
int ret = ARCHIVE_OK;
if((archive = archive_read_new()) == NULL) {
- RET_ERR(PM_ERR_LIBARCHIVE_ERROR, NULL);
+ RET_ERR(PM_ERR_LIBARCHIVE, NULL);
}
archive_read_support_compression_all(archive);
@@ -652,106 +568,158 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(pmpkg_t *pkg)
/** @} */
-/* this function was taken from rpm 4.0.4 and rewritten */
-int _alpm_versioncmp(const char *a, const char *b)
+/** Compare two version strings and determine which one is 'newer'.
+ * Returns a value comparable to the way strcmp works. Returns 1
+ * if a is newer than b, 0 if a and b are the same version, or -1
+ * if b is newer than a.
+ *
+ * This function has been adopted from the rpmvercmp function located
+ * at lib/rpmvercmp.c, and was most recently updated against rpm
+ * version 4.4.2.3. Small modifications have been made to make it more
+ * consistent with the libalpm coding style.
+ */
+int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)
{
- char str1[64], str2[64];
+ char oldch1, oldch2;
+ char *str1, *str2;
char *ptr1, *ptr2;
char *one, *two;
- char *rel1 = NULL, *rel2 = NULL;
- char oldch1, oldch2;
- int is1num, is2num;
int rc;
+ int isnum;
+ int ret = 0;
ALPM_LOG_FUNC;
- if(!strcmp(a,b)) {
- return(0);
+ /* libalpm added code. ensure our strings are not null */
+ if(!a) {
+ if(!b) return(0);
+ return(-1);
}
+ if(!b) return(1);
- strncpy(str1, a, 64);
- str1[63] = 0;
- strncpy(str2, b, 64);
- str2[63] = 0;
+ /* easy comparison to see if versions are identical */
+ if(strcmp(a, b) == 0) return(0);
- /* lose the release number */
- for(one = str1; *one && *one != '-'; one++);
- if(one) {
- *one = '\0';
- rel1 = ++one;
- }
- for(two = str2; *two && *two != '-'; two++);
- if(two) {
- *two = '\0';
- rel2 = ++two;
- }
+ str1 = strdup(a);
+ str2 = strdup(b);
one = str1;
two = str2;
- while(*one || *two) {
+ /* loop through each version segment of str1 and str2 and compare them */
+ while(*one && *two) {
while(*one && !isalnum((int)*one)) one++;
while(*two && !isalnum((int)*two)) two++;
+ /* If we ran to the end of either, we are finished with the loop */
+ if(!(*one && *two)) break;
+
ptr1 = one;
ptr2 = two;
- /* find the next segment for each string */
+ /* grab first completely alpha or completely numeric segment */
+ /* leave one and two pointing to the start of the alpha or numeric */
+ /* segment and walk ptr1 and ptr2 to end of segment */
if(isdigit((int)*ptr1)) {
- is1num = 1;
while(*ptr1 && isdigit((int)*ptr1)) ptr1++;
- } else {
- is1num = 0;
- while(*ptr1 && isalpha((int)*ptr1)) ptr1++;
- }
- if(isdigit((int)*ptr2)) {
- is2num = 1;
while(*ptr2 && isdigit((int)*ptr2)) ptr2++;
+ isnum = 1;
} else {
- is2num = 0;
+ while(*ptr1 && isalpha((int)*ptr1)) ptr1++;
while(*ptr2 && isalpha((int)*ptr2)) ptr2++;
+ isnum = 0;
}
+ /* save character at the end of the alpha or numeric segment */
+ /* so that they can be restored after the comparison */
oldch1 = *ptr1;
*ptr1 = '\0';
oldch2 = *ptr2;
*ptr2 = '\0';
- /* see if we ran out of segments on one string */
- if(one == ptr1 && two != ptr2) {
- return(is2num ? -1 : 1);
+ /* this cannot happen, as we previously tested to make sure that */
+ /* the first string has a non-null segment */
+ if (one == ptr1) {
+ ret = -1; /* arbitrary */
+ goto cleanup;
}
- if(one != ptr1 && two == ptr2) {
- return(is1num ? 1 : -1);
+
+ /* take care of the case where the two version segments are */
+ /* different types: one numeric, the other alpha (i.e. empty) */
+ /* numeric segments are always newer than alpha segments */
+ /* XXX See patch #60884 (and details) from bugzilla #50977. */
+ if (two == ptr2) {
+ ret = isnum ? 1 : -1;
+ goto cleanup;
}
- /* see if we have a type mismatch (ie, one is alpha and one is digits) */
- if(is1num && !is2num) return(1);
- if(!is1num && is2num) return(-1);
+ if (isnum) {
+ /* this used to be done by converting the digit segments */
+ /* to ints using atoi() - it's changed because long */
+ /* digit segments can overflow an int - this should fix that. */
- if(is1num) while(*one == '0') one++;
- if(is2num) while(*two == '0') two++;
+ /* throw away any leading zeros - it's a number, right? */
+ while (*one == '0') one++;
+ while (*two == '0') two++;
+
+ /* whichever number has more digits wins */
+ if (strlen(one) > strlen(two)) {
+ ret = 1;
+ goto cleanup;
+ }
+ if (strlen(two) > strlen(one)) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
- rc = strverscmp(one, two);
- if(rc) return(rc);
+ /* strcmp will return which one is greater - even if the two */
+ /* segments are alpha or if they are numeric. don't return */
+ /* if they are equal because there might be more segments to */
+ /* compare */
+ rc = strcmp(one, two);
+ if (rc) {
+ ret = rc < 1 ? -1 : 1;
+ goto cleanup;
+ }
+ /* restore character that was replaced by null above */
*ptr1 = oldch1;
- *ptr2 = oldch2;
one = ptr1;
+ *ptr2 = oldch2;
two = ptr2;
}
- if((!*one) && (!*two)) {
- /* compare release numbers */
- if(rel1 && rel2 && strlen(rel1) && strlen(rel2)) return(_alpm_versioncmp(rel1, rel2));
- return(0);
+ /* this catches the case where all numeric and alpha segments have */
+ /* compared identically but the segment separating characters were */
+ /* different */
+ if ((!*one) && (!*two)) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* libalpm added code. one version string may have a pkgrel number, the
+ * other may not. unless both have them, we ignore it and return 0. */
+ if( (*one && *one == '-') || (*two && *two == '-') ) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* whichever version still has characters left over wins */
+ if (!*one) {
+ ret = -1;
+ } else {
+ ret = 1;
}
- return(*one ? 1 : -1);
+cleanup:
+ free(str1);
+ free(str2);
+ return(ret);
}
-pmpkg_t *_alpm_pkg_new(const char *name, const char *version)
+pmpkg_t *_alpm_pkg_new(void)
{
pmpkg_t* pkg;
@@ -759,47 +727,56 @@ pmpkg_t *_alpm_pkg_new(const char *name, const char *version)
CALLOC(pkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
- if(name && name[0] != 0) {
- strncpy(pkg->name, name, PKG_NAME_LEN);
- } else {
- pkg->name[0] = '\0';
- }
- if(version && version[0] != 0) {
- strncpy(pkg->version, version, PKG_VERSION_LEN);
- } else {
- pkg->version[0] = '\0';
- }
-
return(pkg);
}
pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
{
- pmpkg_t* newpkg;
+ pmpkg_t *newpkg;
+ alpm_list_t *i;
ALPM_LOG_FUNC;
CALLOC(newpkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
- memcpy(newpkg, pkg, sizeof(pmpkg_t));
+ STRDUP(newpkg->filename, pkg->filename, RET_ERR(PM_ERR_MEMORY, newpkg));
+ STRDUP(newpkg->name, pkg->name, RET_ERR(PM_ERR_MEMORY, newpkg));
+ STRDUP(newpkg->version, pkg->version, RET_ERR(PM_ERR_MEMORY, newpkg));
+ STRDUP(newpkg->desc, pkg->desc, RET_ERR(PM_ERR_MEMORY, newpkg));
+ STRDUP(newpkg->url, pkg->url, RET_ERR(PM_ERR_MEMORY, newpkg));
+ newpkg->builddate = pkg->builddate;
+ newpkg->installdate = pkg->installdate;
+ STRDUP(newpkg->packager, pkg->packager, RET_ERR(PM_ERR_MEMORY, newpkg));
+ STRDUP(newpkg->md5sum, pkg->md5sum, RET_ERR(PM_ERR_MEMORY, newpkg));
+ STRDUP(newpkg->arch, pkg->arch, RET_ERR(PM_ERR_MEMORY, newpkg));
+ newpkg->size = pkg->size;
+ newpkg->isize = pkg->isize;
+ newpkg->scriptlet = pkg->scriptlet;
+ newpkg->force = pkg->force;
+ newpkg->reason = pkg->reason;
+
newpkg->licenses = alpm_list_strdup(alpm_pkg_get_licenses(pkg));
- newpkg->conflicts = alpm_list_strdup(alpm_pkg_get_conflicts(pkg));
+ newpkg->replaces = alpm_list_strdup(alpm_pkg_get_replaces(pkg));
+ newpkg->groups = alpm_list_strdup(alpm_pkg_get_groups(pkg));
newpkg->files = alpm_list_strdup(alpm_pkg_get_files(pkg));
newpkg->backup = alpm_list_strdup(alpm_pkg_get_backup(pkg));
- newpkg->depends = alpm_list_copy_data(alpm_pkg_get_depends(pkg),
- sizeof(pmdepend_t));
+ for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) {
+ newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data));
+ }
newpkg->optdepends = alpm_list_strdup(alpm_pkg_get_optdepends(pkg));
- newpkg->groups = alpm_list_strdup(alpm_pkg_get_groups(pkg));
+ newpkg->conflicts = alpm_list_strdup(alpm_pkg_get_conflicts(pkg));
newpkg->provides = alpm_list_strdup(alpm_pkg_get_provides(pkg));
- newpkg->replaces = alpm_list_strdup(alpm_pkg_get_replaces(pkg));
newpkg->deltas = alpm_list_copy_data(alpm_pkg_get_deltas(pkg),
- sizeof(pmdelta_t));
+ sizeof(pmdelta_t));
+
/* internal */
+ newpkg->origin = pkg->origin;
if(newpkg->origin == PKG_FROM_FILE) {
newpkg->origin_data.file = strdup(pkg->origin_data.file);
} else {
newpkg->origin_data.db = pkg->origin_data.db;
}
+ newpkg->infolevel = pkg->infolevel;
return(newpkg);
}
@@ -812,16 +789,28 @@ void _alpm_pkg_free(pmpkg_t *pkg)
return;
}
+ FREE(pkg->filename);
+ FREE(pkg->name);
+ FREE(pkg->version);
+ FREE(pkg->desc);
+ FREE(pkg->url);
+ FREE(pkg->packager);
+ FREE(pkg->md5sum);
+ FREE(pkg->arch);
FREELIST(pkg->licenses);
+ FREELIST(pkg->replaces);
+ FREELIST(pkg->groups);
FREELIST(pkg->files);
FREELIST(pkg->backup);
- FREELIST(pkg->depends);
+ alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free);
+ alpm_list_free(pkg->depends);
FREELIST(pkg->optdepends);
FREELIST(pkg->conflicts);
- FREELIST(pkg->groups);
FREELIST(pkg->provides);
- FREELIST(pkg->replaces);
- FREELIST(pkg->deltas);
+ alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free);
+ alpm_list_free(pkg->deltas);
+ alpm_list_free(pkg->delta_path);
+
if(pkg->origin == PKG_FROM_FILE) {
FREE(pkg->origin_data.file);
}
@@ -841,7 +830,7 @@ int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg)
}
/* compare versions and see if we need to upgrade */
- cmp = _alpm_versioncmp(alpm_pkg_get_version(pkg), alpm_pkg_get_version(local_pkg));
+ cmp = alpm_pkg_vercmp(alpm_pkg_get_version(pkg), alpm_pkg_get_version(local_pkg));
if(cmp != 0 && pkg->force) {
cmp = 1;
@@ -863,269 +852,15 @@ int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg)
*/
int _alpm_pkg_cmp(const void *p1, const void *p2)
{
- pmpkg_t *pk1 = (pmpkg_t *)p1;
- pmpkg_t *pk2 = (pmpkg_t *)p2;
-
- return(strcmp(alpm_pkg_get_name(pk1), alpm_pkg_get_name(pk2)));
-}
-
-/* Parses the package description file for the current package
- * TODO: this should ALL be in a backend interface (be_files), we should
- * be dealing with the abstracted concepts only in this file
- * Returns: 0 on success, 1 on error
- *
- */
-static int parse_descfile(const char *descfile, pmpkg_t *info)
-{
- FILE* fp = NULL;
- char line[PATH_MAX];
- char *ptr = NULL;
- char *key = NULL;
- int linenum = 0;
-
- ALPM_LOG_FUNC;
-
- if((fp = fopen(descfile, "r")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), descfile, strerror(errno));
- return(-1);
- }
-
- while(!feof(fp)) {
- fgets(line, PATH_MAX, fp);
- linenum++;
- _alpm_strtrim(line);
- if(strlen(line) == 0 || line[0] == '#') {
- continue;
- }
- ptr = line;
- key = strsep(&ptr, "=");
- if(key == NULL || ptr == NULL) {
- _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n",
- info->name[0] != '\0' ? info->name : "error", linenum);
- } else {
- _alpm_strtrim(key);
- _alpm_strtrim(ptr);
- if(!strcmp(key, "pkgname")) {
- strncpy(info->name, ptr, sizeof(info->name));
- } else if(!strcmp(key, "pkgver")) {
- strncpy(info->version, ptr, sizeof(info->version));
- } else if(!strcmp(key, "pkgdesc")) {
- strncpy(info->desc, ptr, sizeof(info->desc));
- } else if(!strcmp(key, "group")) {
- info->groups = alpm_list_add(info->groups, strdup(ptr));
- } else if(!strcmp(key, "url")) {
- strncpy(info->url, ptr, sizeof(info->url));
- } else if(!strcmp(key, "license")) {
- info->licenses = alpm_list_add(info->licenses, strdup(ptr));
- } else if(!strcmp(key, "builddate")) {
- char first = tolower(ptr[0]);
- if(first > 'a' && first < 'z') {
- struct tm tmp_tm = {0}; //initialize to null incase of failure
- setlocale(LC_TIME, "C");
- strptime(ptr, "%a %b %e %H:%M:%S %Y", &tmp_tm);
- info->builddate = mktime(&tmp_tm);
- setlocale(LC_TIME, "");
- } else {
- info->builddate = atol(ptr);
- }
- } else if(!strcmp(key, "packager")) {
- strncpy(info->packager, ptr, sizeof(info->packager));
- } else if(!strcmp(key, "arch")) {
- strncpy(info->arch, ptr, sizeof(info->arch));
- } else if(!strcmp(key, "size")) {
- /* size in the raw package is uncompressed (installed) size */
- info->isize = atol(ptr);
- } else if(!strcmp(key, "depend")) {
- pmdepend_t *dep = alpm_splitdep(ptr);
- info->depends = alpm_list_add(info->depends, dep);
- } else if(!strcmp(key, "optdepend")) {
- info->optdepends = alpm_list_add(info->optdepends, strdup(ptr));
- } else if(!strcmp(key, "conflict")) {
- info->conflicts = alpm_list_add(info->conflicts, strdup(ptr));
- } else if(!strcmp(key, "replaces")) {
- info->replaces = alpm_list_add(info->replaces, strdup(ptr));
- } else if(!strcmp(key, "provides")) {
- info->provides = alpm_list_add(info->provides, strdup(ptr));
- } else if(!strcmp(key, "backup")) {
- info->backup = alpm_list_add(info->backup, strdup(ptr));
- } else {
- _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n",
- info->name[0] != '\0' ? info->name : "error", linenum);
- }
- }
- line[0] = '\0';
- }
- fclose(fp);
- unlink(descfile);
-
- return(0);
-}
-
-
-/**
- * Load a package and create the corresponding pmpkg_t struct.
- * @param pkgfile path to the package file
- * @param full whether to stop the load after metadata is read or continue
- * through the full archive
- * @return An information filled pmpkg_t struct
- */
-pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full)
-{
- int ret = ARCHIVE_OK;
- int config = 0;
- struct archive *archive;
- struct archive_entry *entry;
- pmpkg_t *info = NULL;
- char *descfile = NULL;
- int fd = -1;
- struct stat st;
-
- ALPM_LOG_FUNC;
-
- if(pkgfile == NULL || strlen(pkgfile) == 0) {
- RET_ERR(PM_ERR_WRONG_ARGS, NULL);
- }
-
- if((archive = archive_read_new()) == NULL) {
- RET_ERR(PM_ERR_LIBARCHIVE_ERROR, NULL);
- }
-
- archive_read_support_compression_all(archive);
- archive_read_support_format_all(archive);
-
- if (archive_read_open_filename(archive, pkgfile,
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- RET_ERR(PM_ERR_PKG_OPEN, NULL);
- }
-
- info = _alpm_pkg_new(NULL, NULL);
- if(info == NULL) {
- archive_read_finish(archive);
- RET_ERR(PM_ERR_MEMORY, NULL);
- }
-
- if(stat(pkgfile, &st) == 0) {
- info->size = st.st_size;
- }
-
- /* TODO there is no reason to make temp files to read
- * from a libarchive archive, it can be done by reading
- * directly from the archive
- * See: archive_read_data_into_buffer
- * requires changes 'parse_descfile' as well
- * */
-
- /* If full is false, only read through the archive until we find our needed
- * metadata. If it is true, read through the entire archive, which serves
- * as a verfication of integrity and allows us to create the filelist. */
- while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
- const char *entry_name = archive_entry_pathname(entry);
-
- /* NOTE: we used to look for .FILELIST, but it is easier (and safer) for
- * us to just generate this on our own. */
- if(strcmp(entry_name, ".PKGINFO") == 0) {
- /* extract this file into /tmp. it has info for us */
- descfile = strdup("/tmp/alpm_XXXXXX");
- fd = mkstemp(descfile);
- if(archive_read_data_into_fd(archive, fd) != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("error extracting package description file to %s\n"),
- descfile);
- goto pkg_invalid;
- }
- /* parse the info file */
- if(parse_descfile(descfile, info) == -1) {
- _alpm_log(PM_LOG_ERROR, _("could not parse package description file in %s\n"),
- pkgfile);
- goto pkg_invalid;
- }
- if(!strlen(info->name)) {
- _alpm_log(PM_LOG_ERROR, _("missing package name in %s\n"), pkgfile);
- goto pkg_invalid;
- }
- if(!strlen(info->version)) {
- _alpm_log(PM_LOG_ERROR, _("missing package version in %s\n"), pkgfile);
- goto pkg_invalid;
- }
- config = 1;
- unlink(descfile);
- FREE(descfile);
- close(fd);
- continue;
- } else if(strcmp(entry_name, ".INSTALL") == 0) {
- info->scriptlet = 1;
- } else if(*entry_name == '.') {
- /* for now, ignore all files starting with '.' that haven't
- * already been handled (for future possibilities) */
- } else {
- /* Keep track of all files for filelist generation */
- info->files = alpm_list_add(info->files, strdup(entry_name));
- }
-
- if(archive_read_data_skip(archive)) {
- _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"),
- pkgfile, archive_error_string(archive));
- pm_errno = PM_ERR_LIBARCHIVE_ERROR;
- goto error;
- }
-
- /* if we are not doing a full read, see if we have all we need */
- if(!full && config) {
- break;
- }
- }
-
- if(ret != ARCHIVE_EOF && ret != ARCHIVE_OK) { /* An error occured */
- _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"),
- pkgfile, archive_error_string(archive));
- pm_errno = PM_ERR_LIBARCHIVE_ERROR;
- goto error;
- }
-
- if(!config) {
- _alpm_log(PM_LOG_ERROR, _("missing package metadata in %s\n"), pkgfile);
- goto pkg_invalid;
- }
-
- archive_read_finish(archive);
-
- /* internal fields for package struct */
- info->origin = PKG_FROM_FILE;
- info->origin_data.file = strdup(pkgfile);
-
- if(full) {
- /* "checking for conflicts" requires a sorted list, so we ensure that here */
- _alpm_log(PM_LOG_DEBUG, "sorting package filelist for %s\n", pkgfile);
- info->files = alpm_list_msort(info->files, alpm_list_count(info->files),
- _alpm_str_cmp);
- info->infolevel = INFRQ_ALL;
- } else {
- /* get rid of any partial filelist we may have collected, as it is invalid */
- FREELIST(info->files);
- info->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS;
- }
-
- return(info);
-
-pkg_invalid:
- pm_errno = PM_ERR_PKG_INVALID;
- if(descfile) {
- unlink(descfile);
- FREE(descfile);
- }
- if(fd != -1) {
- close(fd);
- }
-error:
- _alpm_pkg_free(info);
- archive_read_finish(archive);
-
- return(NULL);
+ pmpkg_t *pkg1 = (pmpkg_t *)p1;
+ pmpkg_t *pkg2 = (pmpkg_t *)p2;
+ return(strcmp(alpm_pkg_get_name(pkg1), alpm_pkg_get_name(pkg2)));
}
/* Test for existence of a package in a alpm_list_t*
* of pmpkg_t*
*/
-pmpkg_t *_alpm_pkg_find(const char *needle, alpm_list_t *haystack)
+pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle)
{
alpm_list_t *lp;
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index d6c3eff9..ddf1d073 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -33,30 +33,17 @@ typedef enum _pmpkgfrom_t {
PKG_FROM_FILE
} pmpkgfrom_t;
-/* Packages */
-#define PKG_FILENAME_LEN 512
-#define PKG_NAME_LEN 256
-#define PKG_VERSION_LEN 64
-#define PKG_FULLNAME_LEN (PKG_NAME_LEN + PKG_VERSION_LEN)
-#define PKG_DESC_LEN 512
-#define PKG_URL_LEN 256
-#define PKG_DATE_LEN 32
-#define PKG_TYPE_LEN 32
-#define PKG_PACKAGER_LEN 64
-#define PKG_MD5SUM_LEN 33
-#define PKG_ARCH_LEN 32
-
struct __pmpkg_t {
- char filename[PKG_FILENAME_LEN];
- char name[PKG_NAME_LEN];
- char version[PKG_VERSION_LEN];
- char desc[PKG_DESC_LEN];
- char url[PKG_URL_LEN];
+ char *filename;
+ char *name;
+ char *version;
+ char *desc;
+ char *url;
time_t builddate;
time_t installdate;
- char packager[PKG_PACKAGER_LEN];
- char md5sum[PKG_MD5SUM_LEN];
- char arch[PKG_ARCH_LEN];
+ char *packager;
+ char *md5sum;
+ char *arch;
unsigned long size;
unsigned long isize;
unsigned short scriptlet;
@@ -83,16 +70,16 @@ struct __pmpkg_t {
char *file;
} origin_data;
pmdbinfrq_t infolevel;
+ unsigned long download_size;
+ alpm_list_t *delta_path;
};
-int _alpm_versioncmp(const char *a, const char *b);
-pmpkg_t* _alpm_pkg_new(const char *name, const char *version);
+pmpkg_t* _alpm_pkg_new(void);
pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg);
void _alpm_pkg_free(pmpkg_t *pkg);
int _alpm_pkg_cmp(const void *p1, const void *p2);
int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg);
-pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full);
-pmpkg_t *_alpm_pkg_find(const char *needle, alpm_list_t *haystack);
+pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle);
int _alpm_pkg_should_ignore(pmpkg_t *pkg);
#endif /* _ALPM_PACKAGE_H */
diff --git a/lib/libalpm/po/POTFILES.in b/lib/libalpm/po/POTFILES.in
index 80130f24..35bd864b 100644
--- a/lib/libalpm/po/POTFILES.in
+++ b/lib/libalpm/po/POTFILES.in
@@ -10,6 +10,7 @@ lib/libalpm/conflict.c
lib/libalpm/db.c
lib/libalpm/delta.c
lib/libalpm/deps.c
+lib/libalpm/dload.c
lib/libalpm/error.c
lib/libalpm/group.c
lib/libalpm/handle.c
@@ -17,7 +18,6 @@ lib/libalpm/log.c
lib/libalpm/md5.c
lib/libalpm/package.c
lib/libalpm/remove.c
-lib/libalpm/server.c
lib/libalpm/sync.c
lib/libalpm/trans.c
lib/libalpm/util.c
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index a0f9963a..625abe67 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -37,7 +37,6 @@
#include "alpm_list.h"
#include "trans.h"
#include "util.h"
-#include "error.h"
#include "log.h"
#include "backup.h"
#include "package.h"
@@ -57,7 +56,7 @@ int _alpm_remove_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name)
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
- if(_alpm_pkg_find(name, trans->packages)) {
+ if(_alpm_pkg_find(trans->packages, name)) {
RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
}
@@ -82,6 +81,60 @@ int _alpm_remove_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name)
return(0);
}
+static void remove_prepare_cascade(pmtrans_t *trans, pmdb_t *db,
+ alpm_list_t *lp)
+{
+ ALPM_LOG_FUNC;
+
+ while(lp) {
+ alpm_list_t *i;
+ for(i = lp; i; i = i->next) {
+ pmdepmissing_t *miss = (pmdepmissing_t *)i->data;
+ pmpkg_t *info = _alpm_db_get_pkgfromcache(db, miss->target);
+ if(info) {
+ if(!_alpm_pkg_find(trans->packages, alpm_pkg_get_name(info))) {
+ _alpm_log(PM_LOG_DEBUG, "pulling %s in the targets list\n",
+ alpm_pkg_get_name(info));
+ trans->packages = alpm_list_add(trans->packages, _alpm_pkg_dup(info));
+ }
+ } else {
+ _alpm_log(PM_LOG_ERROR, _("could not find %s in database -- skipping\n"),
+ miss->target);
+ }
+ }
+ alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
+ alpm_list_free(lp);
+ lp = alpm_checkdeps(db, 1, trans->packages, NULL);
+ }
+}
+
+static void remove_prepare_keep_needed(pmtrans_t *trans, pmdb_t *db,
+ alpm_list_t *lp)
+{
+ ALPM_LOG_FUNC;
+
+ /* Remove needed packages (which break dependencies) from the target list */
+ while(lp != NULL) {
+ alpm_list_t *i;
+ for(i = lp; i; i = i->next) {
+ pmdepmissing_t *miss = (pmdepmissing_t *)i->data;
+ void *vpkg;
+ pmpkg_t *pkg = _alpm_pkg_find(trans->packages, miss->causingpkg);
+ trans->packages = alpm_list_remove(trans->packages, pkg, _alpm_pkg_cmp,
+ &vpkg);
+ pkg = vpkg;
+ if(pkg) {
+ _alpm_log(PM_LOG_WARNING, "removing %s from the target-list\n",
+ alpm_pkg_get_name(pkg));
+ _alpm_pkg_free(pkg);
+ }
+ }
+ alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
+ alpm_list_free(lp);
+ lp = alpm_checkdeps(db, 1, trans->packages, NULL);
+ }
+}
+
int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
{
alpm_list_t *lp;
@@ -96,37 +149,30 @@ int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
return(0);
}
+ if((trans->flags & PM_TRANS_FLAG_RECURSE) && !(trans->flags & PM_TRANS_FLAG_CASCADE)) {
+ _alpm_log(PM_LOG_DEBUG, "finding removable dependencies\n");
+ _alpm_recursedeps(db, trans->packages, trans->flags & PM_TRANS_FLAG_RECURSEALL);
+ }
+
if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
EVENT(trans, PM_TRANS_EVT_CHECKDEPS_START, NULL, NULL);
_alpm_log(PM_LOG_DEBUG, "looking for unsatisfied dependencies\n");
lp = alpm_checkdeps(db, 1, trans->packages, NULL);
if(lp != NULL) {
+
if(trans->flags & PM_TRANS_FLAG_CASCADE) {
- while(lp) {
- alpm_list_t *i;
- for(i = lp; i; i = i->next) {
- pmdepmissing_t *miss = (pmdepmissing_t *)i->data;
- pmpkg_t *info = _alpm_db_get_pkgfromcache(db, miss->target);
- if(info) {
- if(!_alpm_pkg_find(alpm_pkg_get_name(info), trans->packages)) {
- _alpm_log(PM_LOG_DEBUG, "pulling %s in the targets list\n",
- alpm_pkg_get_name(info));
- trans->packages = alpm_list_add(trans->packages, _alpm_pkg_dup(info));
- }
- } else {
- _alpm_log(PM_LOG_ERROR, _("could not find %s in database -- skipping\n"),
- miss->target);
- }
- }
- FREELIST(lp);
- lp = alpm_checkdeps(db, 1, trans->packages, NULL);
- }
+ remove_prepare_cascade(trans, db, lp);
+ } else if (trans->flags & PM_TRANS_FLAG_UNNEEDED) {
+ /* Remove needed packages (which would break dependencies)
+ * from the target list */
+ remove_prepare_keep_needed(trans, db, lp);
} else {
if(data) {
*data = lp;
} else {
- FREELIST(lp);
+ alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
+ alpm_list_free(lp);
}
RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1);
}
@@ -135,14 +181,15 @@ int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
/* re-order w.r.t. dependencies */
_alpm_log(PM_LOG_DEBUG, "sorting by dependencies\n");
- lp = _alpm_sortbydeps(trans->packages, PM_TRANS_TYPE_REMOVE);
+ lp = _alpm_sortbydeps(trans->packages, 1);
/* free the old alltargs */
alpm_list_free(trans->packages);
trans->packages = lp;
- if(trans->flags & PM_TRANS_FLAG_RECURSE) {
+ /* -Rcs == -Rc then -Rs */
+ if((trans->flags & PM_TRANS_FLAG_CASCADE) && (trans->flags & PM_TRANS_FLAG_RECURSE)) {
_alpm_log(PM_LOG_DEBUG, "finding removable dependencies\n");
- _alpm_recursedeps(db, trans->packages, 0);
+ _alpm_recursedeps(db, trans->packages, trans->flags & PM_TRANS_FLAG_RECURSEALL);
}
if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
diff --git a/lib/libalpm/server.c b/lib/libalpm/server.c
deleted file mode 100644
index 4bccf3ca..00000000
--- a/lib/libalpm/server.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * server.c
- *
- * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <errno.h>
-#include <time.h>
-#include <string.h>
-#include <limits.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <download.h>
-
-/* libalpm */
-#include "server.h"
-#include "alpm_list.h"
-#include "error.h"
-#include "log.h"
-#include "alpm.h"
-#include "util.h"
-#include "handle.h"
-#include "package.h"
-
-pmserver_t *_alpm_server_new(const char *url)
-{
- struct url *u;
- pmserver_t *server;
-
- ALPM_LOG_FUNC;
-
- CALLOC(server, 1, sizeof(pmserver_t), RET_ERR(PM_ERR_MEMORY, NULL));
-
- u = downloadParseURL(url);
- if(!u) {
- _alpm_log(PM_LOG_ERROR, _("url '%s' is invalid, ignoring\n"), url);
- RET_ERR(PM_ERR_SERVER_BAD_URL, NULL);
- }
- if(strlen(u->scheme) == 0) {
- _alpm_log(PM_LOG_WARNING, _("url scheme not specified, assuming http\n"));
- strcpy(u->scheme, "http");
- }
-
- if(strcmp(u->scheme,"ftp") == 0 && strlen(u->user) == 0) {
- strcpy(u->user, "anonymous");
- strcpy(u->pwd, "libalpm@guest");
- }
-
- /* remove trailing slashes, just to clean up the rest of the code */
- for(int i = strlen(u->doc) - 1; u->doc[i] == '/'; --i)
- u->doc[i] = '\0';
-
- server->s_url = u;
-
- return server;
-}
-
-void _alpm_server_free(pmserver_t *server)
-{
- ALPM_LOG_FUNC;
-
- if(server == NULL) {
- return;
- }
-
- /* free memory */
- downloadFreeURL(server->s_url);
- FREE(server);
-}
-
-/* remove filename info from "s_url->doc" and return it */
-static char *strip_filename(pmserver_t *server)
-{
- char *p = NULL, *fname = NULL;
- if(!server) {
- return(NULL);
- }
-
- p = strrchr(server->s_url->doc, '/');
- if(p && *(++p)) {
- fname = strdup(p);
- _alpm_log(PM_LOG_DEBUG, "stripping '%s' from '%s'\n",
- fname, server->s_url->doc);
- *p = 0;
- }
-
- /* s_url->doc now contains ONLY path information. return value
- * if the file information from the original URL */
- return(fname);
-}
-
-/* Return a 'struct url' for this server, for downloading 'filename'. */
-static struct url *url_for_file(pmserver_t *server, const char *filename)
-{
- struct url *ret = NULL;
- char *doc = NULL;
- int doclen = 0;
-
- doclen = strlen(server->s_url->doc) + strlen(filename) + 2;
- CALLOC(doc, doclen, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL));
-
- snprintf(doc, doclen, "%s/%s", server->s_url->doc, filename);
- ret = downloadMakeURL(server->s_url->scheme,
- server->s_url->host,
- server->s_url->port,
- doc,
- server->s_url->user,
- server->s_url->pwd);
- FREE(doc);
- return(ret);
-}
-
-/*
- * Download a list of files from a list of servers
- * - if one server fails, we try the next one in the list
- * - if *dl_total is non-NULL, then it will be used as the starting
- * download amount when TotalDownload is set. It will also be
- * set to the final download amount for the calling function to use.
- * - totalsize is the total download size for use when TotalDownload
- * is set. Use 0 if the total download size is not known.
- *
- * RETURN: 0 for successful download, 1 on error
- */
-int _alpm_downloadfiles(alpm_list_t *servers, const char *localpath,
- alpm_list_t *files, int *dl_total, unsigned long totalsize)
-{
- return(_alpm_downloadfiles_forreal(servers, localpath, files, 0, NULL,
- dl_total, totalsize));
-}
-
-/*
- * This is the real downloadfiles, used directly by sync_synctree() to check
- * modtimes on remote files.
- * - if mtime1 is non-NULL, then only download files if they are different
- * than mtime1.
- * - if *mtime2 is non-NULL, it will be filled with the mtime of the remote
- * file.
- * - if *dl_total is non-NULL, then it will be used as the starting
- * download amount when TotalDownload is set. It will also be
- * set to the final download amount for the calling function to use.
- * - totalsize is the total download size for use when TotalDownload
- * is set. Use 0 if the total download size is not known.
- *
- * RETURN: 0 for successful download
- * 1 if the mtimes are identical
- * -1 on error
- */
-int _alpm_downloadfiles_forreal(alpm_list_t *servers, const char *localpath,
- alpm_list_t *files, time_t mtime1, time_t *mtime2, int *dl_total,
- unsigned long totalsize)
-{
- int dl_thisfile = 0;
- alpm_list_t *lp;
- int done = 0;
- alpm_list_t *complete = NULL;
- alpm_list_t *i;
-
- ALPM_LOG_FUNC;
-
- if(files == NULL) {
- return(0);
- }
-
- for(i = servers; i && !done; i = i->next) {
- pmserver_t *server = i->data;
-
- /* get each file in the list */
- for(lp = files; lp; lp = lp->next) {
- struct url *fileurl = NULL;
- char realfile[PATH_MAX];
- char output[PATH_MAX];
- char *fn = (char *)lp->data;
- char pkgname[PKG_NAME_LEN];
-
- fileurl = url_for_file(server, fn);
- if(!fileurl) {
- return(-1);
- }
-
- /* pass the raw filename for passing to the callback function */
- strncpy(pkgname, fn, PKG_NAME_LEN);
- _alpm_log(PM_LOG_DEBUG, "using '%s' for download progress\n", pkgname);
-
- snprintf(realfile, PATH_MAX, "%s%s", localpath, fn);
- snprintf(output, PATH_MAX, "%s%s.part", localpath, fn);
-
- if(alpm_list_find_str(complete, fn)) {
- continue;
- }
-
- if(!handle->xfercommand || !strcmp(fileurl->scheme, "file")) {
- FILE *dlf, *localf = NULL;
- struct url_stat ust;
- struct stat st;
- int chk_resume = 0;
-
- if(stat(output, &st) == 0 && st.st_size > 0) {
- _alpm_log(PM_LOG_DEBUG, "existing file found, using it\n");
- fileurl->offset = (off_t)st.st_size;
- dl_thisfile = st.st_size;
- if (dl_total != NULL) {
- *dl_total += st.st_size;
- }
- localf = fopen(output, "a");
- chk_resume = 1;
- } else {
- fileurl->offset = (off_t)0;
- dl_thisfile = 0;
- }
-
- /* libdownload does not reset the error code, reset it in
- * the case of previous errors */
- downloadLastErrCode = 0;
-
- /* 10s timeout - TODO make a config option */
- downloadTimeout = 10000;
-
- dlf = downloadXGet(fileurl, &ust, (handle->nopassiveftp ? "" : "p"));
-
- if(downloadLastErrCode != 0 || dlf == NULL) {
- const char *host = _("disk");
- if(strcmp(SCHEME_FILE, fileurl->scheme) != 0) {
- host = fileurl->host;
- }
- _alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"),
- fn, host, downloadLastErrString);
- if(localf != NULL) {
- fclose(localf);
- }
- /* try the next server */
- downloadFreeURL(fileurl);
- continue;
- } else {
- _alpm_log(PM_LOG_DEBUG, "connected to %s successfully\n", fileurl->host);
- }
-
- if(ust.mtime && mtime1 && ust.mtime == mtime1) {
- _alpm_log(PM_LOG_DEBUG, "mtimes are identical, skipping %s\n", fn);
- complete = alpm_list_add(complete, fn);
- if(localf != NULL) {
- fclose(localf);
- }
- if(dlf != NULL) {
- fclose(dlf);
- }
- downloadFreeURL(fileurl);
- return(1);
- }
-
- if(ust.mtime && mtime2) {
- *mtime2 = ust.mtime;
- }
-
- if(chk_resume && fileurl->offset == 0) {
- _alpm_log(PM_LOG_WARNING, _("cannot resume download, starting over\n"));
- if(localf != NULL) {
- fclose(localf);
- localf = NULL;
- }
- }
-
- if(localf == NULL) {
- _alpm_rmrf(output);
- fileurl->offset = (off_t)0;
- dl_thisfile = 0;
- localf = fopen(output, "w");
- if(localf == NULL) { /* still null? */
- _alpm_log(PM_LOG_ERROR, _("cannot write to file '%s'\n"), output);
- if(dlf != NULL) {
- fclose(dlf);
- }
- downloadFreeURL(fileurl);
- return(-1);
- }
- }
-
- /* Progress 0 - initialize */
- if(handle->dlcb) {
- handle->dlcb(pkgname, 0, ust.size, dl_total ? *dl_total : 0,
- totalsize);
- }
-
- int nread = 0;
- char buffer[PM_DLBUF_LEN];
- while((nread = fread(buffer, 1, PM_DLBUF_LEN, dlf)) > 0) {
- if(ferror(dlf)) {
- _alpm_log(PM_LOG_ERROR, _("error downloading '%s': %s\n"),
- fn, downloadLastErrString);
- fclose(localf);
- fclose(dlf);
- downloadFreeURL(fileurl);
- return(-1);
- }
-
- int nwritten = 0;
- while(nwritten < nread) {
- nwritten += fwrite(buffer, 1, (nread - nwritten), localf);
- if(ferror(localf)) {
- _alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"),
- realfile, strerror(errno));
- fclose(localf);
- fclose(dlf);
- downloadFreeURL(fileurl);
- return(-1);
- }
- }
-
- if(nwritten != nread) {
-
- }
- dl_thisfile += nread;
- if (dl_total != NULL) {
- *dl_total += nread;
- }
-
- if(handle->dlcb) {
- handle->dlcb(pkgname, dl_thisfile, ust.size,
- dl_total ? *dl_total : 0, totalsize);
- }
- }
-
- downloadFreeURL(fileurl);
- fclose(localf);
- fclose(dlf);
- rename(output, realfile);
- complete = alpm_list_add(complete, fn);
- } else {
- int ret;
- int usepart = 0;
- char *ptr1, *ptr2;
- char origCmd[PATH_MAX];
- char parsedCmd[PATH_MAX] = "";
- char url[PATH_MAX];
- char cwd[PATH_MAX];
-
- /* build the full download url */
- snprintf(url, PATH_MAX, "%s://%s%s", fileurl->scheme,
- fileurl->host, fileurl->doc);
- /* we don't need this anymore */
- downloadFreeURL(fileurl);
-
- /* replace all occurrences of %o with fn.part */
- strncpy(origCmd, handle->xfercommand, sizeof(origCmd));
- ptr1 = origCmd;
- while((ptr2 = strstr(ptr1, "%o"))) {
- usepart = 1;
- ptr2[0] = '\0';
- strcat(parsedCmd, ptr1);
- strcat(parsedCmd, output);
- ptr1 = ptr2 + 2;
- }
- strcat(parsedCmd, ptr1);
- /* replace all occurrences of %u with the download URL */
- strncpy(origCmd, parsedCmd, sizeof(origCmd));
- parsedCmd[0] = '\0';
- ptr1 = origCmd;
- while((ptr2 = strstr(ptr1, "%u"))) {
- ptr2[0] = '\0';
- strcat(parsedCmd, ptr1);
- strcat(parsedCmd, url);
- ptr1 = ptr2 + 2;
- }
- strcat(parsedCmd, ptr1);
- /* cwd to the download directory */
- getcwd(cwd, PATH_MAX);
- if(chdir(localpath)) {
- _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), localpath);
- return(PM_ERR_CONNECT_FAILED);
- }
- /* execute the parsed command via /bin/sh -c */
- _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd);
- ret = system(parsedCmd);
- if(ret == -1) {
- _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!\n"));
- return(PM_ERR_FORK_FAILED);
- } else if(ret != 0) {
- /* download failed */
- _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero status code (%d)\n", ret);
- } else {
- /* download was successful */
- complete = alpm_list_add(complete, fn);
- if(usepart) {
- rename(output, realfile);
- }
- }
- chdir(cwd);
- }
- }
-
- if(alpm_list_count(complete) == alpm_list_count(files)) {
- done = 1;
- }
- }
- alpm_list_free(complete);
-
- return(done ? 0 : -1);
-}
-
-/** Fetch a remote pkg.
- * @param url URL of the package to download
- * @return the downloaded filepath on success, NULL on error
- * @addtogroup alpm_misc
- */
-char SYMEXPORT *alpm_fetch_pkgurl(const char *url)
-{
- pmserver_t *server;
- char *filename, *filepath;
- const char *cachedir;
-
- ALPM_LOG_FUNC;
-
- if(strstr(url, "://") == NULL) {
- _alpm_log(PM_LOG_DEBUG, "Invalid URL passed to alpm_fetch_pkgurl\n");
- return(NULL);
- }
-
- server = _alpm_server_new(url);
- if(!server) {
- return(NULL);
- }
-
- /* strip path information from the filename */
- filename = strip_filename(server);
- if(!filename) {
- _alpm_log(PM_LOG_ERROR, _("URL does not contain a file for download\n"));
- return(NULL);
- }
-
- /* find a valid cache dir to download to */
- cachedir = _alpm_filecache_setup();
-
- /* TODO this seems like needless complexity just to download one file */
- alpm_list_t *servers = alpm_list_add(NULL, server);
- alpm_list_t *files = alpm_list_add(NULL, filename);
-
- /* download the file */
- if(_alpm_downloadfiles(servers, cachedir, files, NULL, 0)) {
- _alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url);
- return(NULL);
- }
- _alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", filename);
- alpm_list_free(files);
- alpm_list_free(servers);
- _alpm_server_free(server);
-
- /* we should be able to find the file the second time around */
- filepath = _alpm_filecache_find(filename);
- return(filepath);
-}
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/server.h b/lib/libalpm/server.h
deleted file mode 100644
index b82fcb09..00000000
--- a/lib/libalpm/server.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * server.h
- *
- * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef _ALPM_SERVER_H
-#define _ALPM_SERVER_H
-
-#include "alpm_list.h"
-#include "alpm.h"
-
-#include <time.h>
-#include <download.h>
-
-/* Servers */
-struct __pmserver_t {
- /* useless abstraction now? */
- struct url *s_url;
-};
-
-#define PM_DLBUF_LEN (1024 * 10)
-
-pmserver_t *_alpm_server_new(const char *url);
-void _alpm_server_free(pmserver_t *server);
-int _alpm_downloadfiles(alpm_list_t *servers, const char *localpath,
- alpm_list_t *files, int *dl_total, unsigned long totalsize);
-int _alpm_downloadfiles_forreal(alpm_list_t *servers, const char *localpath,
- alpm_list_t *files, time_t mtime1, time_t *mtime2, int *dl_total,
- unsigned long totalsize);
-
-#endif /* _ALPM_SERVER_H */
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index a927f61b..0d6a6ee3 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -34,7 +34,6 @@
#include "sync.h"
#include "alpm_list.h"
#include "log.h"
-#include "error.h"
#include "package.h"
#include "db.h"
#include "cache.h"
@@ -44,10 +43,10 @@
#include "util.h"
#include "handle.h"
#include "alpm.h"
-#include "server.h"
+#include "dload.h"
#include "delta.h"
-pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data)
+pmsyncpkg_t *_alpm_sync_new(pmpkgreason_t newreason, pmpkg_t *spkg, alpm_list_t *removes)
{
pmsyncpkg_t *sync;
@@ -55,9 +54,9 @@ pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data)
CALLOC(sync, 1, sizeof(pmsyncpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
- sync->type = type;
+ sync->newreason = newreason;
sync->pkg = spkg;
- sync->data = data;
+ sync->removes = removes;
return(sync);
}
@@ -70,32 +69,11 @@ void _alpm_sync_free(pmsyncpkg_t *sync)
return;
}
- /* TODO wow this is ugly */
- if(sync->type == PM_SYNC_TYPE_REPLACE) {
- alpm_list_free_inner(sync->data, (alpm_list_fn_free)_alpm_pkg_free);
- alpm_list_free(sync->data);
- sync->data = NULL;
- } else {
- _alpm_pkg_free(sync->data);
- sync->data = NULL;
- }
+ alpm_list_free(sync->removes);
+ sync->removes = NULL;
FREE(sync);
}
-static void synclist_free(alpm_list_t *syncpkgs)
-{
- if(syncpkgs) {
- alpm_list_t *tmp;
- for(tmp = syncpkgs; tmp; tmp = alpm_list_next(tmp)) {
- if(tmp->data) {
- _alpm_sync_free(tmp->data);
- }
- }
- alpm_list_free(syncpkgs);
- }
-
-}
-
/* Find recommended replacements for packages during a sync.
*/
static int find_replacements(pmtrans_t *trans, pmdb_t *db_local,
@@ -147,27 +125,29 @@ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local,
* the package to replace.
*/
pmsyncpkg_t *sync;
- pmpkg_t *dummy = _alpm_pkg_dup(lpkg);
- if(dummy == NULL) {
- pm_errno = PM_ERR_MEMORY;
- synclist_free(*syncpkgs);
- return(-1);
- }
+
/* check if spkg->name is already in the packages list. */
+ /* TODO: same package name doesn't mean same package */
sync = _alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg));
if(sync) {
- /* found it -- just append to the replaces list */
- sync->data = alpm_list_add(sync->data, dummy);
+ /* found it -- just append to the removes list */
+ sync->removes = alpm_list_add(sync->removes, lpkg);
+ /* check the to-be-replaced package's reason field */
+ if(lpkg->reason == PM_PKG_REASON_EXPLICIT) {
+ sync->newreason = PM_PKG_REASON_EXPLICIT;
+ }
} else {
/* none found -- enter pkg into the final sync list */
- sync = _alpm_sync_new(PM_SYNC_TYPE_REPLACE, spkg, NULL);
+ /* copy over reason */
+ sync = _alpm_sync_new(alpm_pkg_get_reason(lpkg), spkg, NULL);
if(sync == NULL) {
- _alpm_pkg_free(dummy);
pm_errno = PM_ERR_MEMORY;
- synclist_free(*syncpkgs);
+ alpm_list_free_inner(*syncpkgs, (alpm_list_fn_free)_alpm_sync_free);
+ alpm_list_free(*syncpkgs);
+ *syncpkgs = NULL;
return(-1);
}
- sync->data = alpm_list_add(NULL, dummy);
+ sync->removes = alpm_list_add(NULL, lpkg);
*syncpkgs = alpm_list_add(*syncpkgs, sync);
}
_alpm_log(PM_LOG_DEBUG, "%s-%s elected for removal (to be replaced by %s-%s)\n",
@@ -180,6 +160,35 @@ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local,
return(0);
}
+/** Check for new version of pkg in sync repos
+ * (only the first occurrence is considered in sync)
+ */
+pmpkg_t SYMEXPORT *alpm_sync_newversion(pmpkg_t *pkg, alpm_list_t *dbs_sync)
+{
+ alpm_list_t *i;
+ pmpkg_t *spkg = NULL;
+
+ for(i = dbs_sync; !spkg && i; i = i->next) {
+ spkg = _alpm_db_get_pkgfromcache(i->data, alpm_pkg_get_name(pkg));
+ }
+
+ if(spkg == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "'%s' not found in sync db => no upgrade\n",
+ alpm_pkg_get_name(pkg));
+ return(NULL);
+ }
+
+ /* compare versions and see if spkg is an upgrade */
+ if(_alpm_pkg_compare_versions(pkg, spkg)) {
+ _alpm_log(PM_LOG_DEBUG, "new version of '%s' found (%s => %s)\n",
+ alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg),
+ alpm_pkg_get_version(spkg));
+ return(spkg);
+ } else {
+ return(NULL);
+ }
+}
+
/** Get a list of upgradable packages on the current system
* Adds out of date packages to *list.
* @arg list pointer to a list of pmsyncpkg_t.
@@ -193,7 +202,7 @@ int SYMEXPORT alpm_sync_sysupgrade(pmdb_t *db_local,
int _alpm_sync_sysupgrade(pmtrans_t *trans,
pmdb_t *db_local, alpm_list_t *dbs_sync, alpm_list_t **syncpkgs)
{
- alpm_list_t *i, *j;
+ alpm_list_t *i, *j, *replaced = NULL;
ALPM_LOG_FUNC;
@@ -205,76 +214,61 @@ int _alpm_sync_sysupgrade(pmtrans_t *trans,
return(-1);
}
- /* match installed packages with the sync dbs and compare versions */
+ /* compute the to-be-replaced packages for efficiency */
+ for(i = *syncpkgs; i; i = i->next) {
+ pmsyncpkg_t *sync = i->data;
+ for(j = sync->removes; j; j = j->next) {
+ replaced = alpm_list_add(replaced, j->data);
+ }
+ }
+
+ /* for all not-replaced local package we check for upgrade */
_alpm_log(PM_LOG_DEBUG, "checking for package upgrades\n");
for(i = _alpm_db_get_pkgcache(db_local); i; i = i->next) {
- int replace = 0;
pmpkg_t *local = i->data;
- pmpkg_t *spkg = NULL;
- pmsyncpkg_t *sync;
- for(j = dbs_sync; !spkg && j; j = j->next) {
- spkg = _alpm_db_get_pkgfromcache(j->data, alpm_pkg_get_name(local));
- }
- if(spkg == NULL) {
- _alpm_log(PM_LOG_DEBUG, "'%s' not found in sync db -- skipping\n",
- alpm_pkg_get_name(local));
- continue;
- }
-
- /* we don't care about a to-be-replaced package's newer version */
- for(j = *syncpkgs; j && !replace; j=j->next) {
- sync = j->data;
- if(sync->type == PM_SYNC_TYPE_REPLACE) {
- if(_alpm_pkg_find(alpm_pkg_get_name(spkg), sync->data)) {
- replace = 1;
- }
- }
- }
- if(replace) {
+ if(_alpm_pkg_find(replaced, alpm_pkg_get_name(local))) {
_alpm_log(PM_LOG_DEBUG, "'%s' is already elected for removal -- skipping\n",
alpm_pkg_get_name(local));
continue;
}
- /* compare versions and see if we need to upgrade */
- if(_alpm_pkg_compare_versions(local, spkg)) {
- _alpm_log(PM_LOG_DEBUG, "%s elected for upgrade (%s => %s)\n",
- alpm_pkg_get_name(local), alpm_pkg_get_version(local),
- alpm_pkg_get_version(spkg));
- if(!_alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg))) {
- /* If package is in the ignorepkg list, skip it */
- if(_alpm_pkg_should_ignore(spkg)) {
- _alpm_log(PM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"),
- alpm_pkg_get_name(local), alpm_pkg_get_version(local),
- alpm_pkg_get_version(spkg));
- continue;
- }
+ pmpkg_t *spkg = alpm_sync_newversion(local, dbs_sync);
+ if(spkg) {
+ /* we found a new version */
+ /* skip packages in IgnorePkg or in IgnoreGroup */
+ if(_alpm_pkg_should_ignore(spkg)) {
+ _alpm_log(PM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"),
+ alpm_pkg_get_name(local), alpm_pkg_get_version(local),
+ alpm_pkg_get_version(spkg));
+ continue;
+ }
- pmpkg_t *tmp = _alpm_pkg_dup(local);
- if(tmp == NULL) {
- pm_errno = PM_ERR_MEMORY;
- synclist_free(*syncpkgs);
- return(-1);
- }
- sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, tmp);
- if(sync == NULL) {
- _alpm_pkg_free(tmp);
- pm_errno = PM_ERR_MEMORY;
- synclist_free(*syncpkgs);
- return(-1);
- }
- *syncpkgs = alpm_list_add(*syncpkgs, sync);
+ /* add the upgrade package to our pmsyncpkg_t list */
+ if(_alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg))) {
+ /* avoid duplicated targets */
+ continue;
+ }
+ /* we can set any reason here, it will be overridden by add_commit */
+ pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_EXPLICIT, spkg, NULL);
+ if(sync == NULL) {
+ alpm_list_free_inner(*syncpkgs, (alpm_list_fn_free)_alpm_sync_free);
+ alpm_list_free(*syncpkgs);
+ *syncpkgs = NULL;
+ alpm_list_free(replaced);
+ return(-1);
}
+ *syncpkgs = alpm_list_add(*syncpkgs, sync);
}
}
+ alpm_list_free(replaced);
return(0);
}
int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, char *name)
{
- char targline[PKG_FULLNAME_LEN];
+ char *targline;
char *targ;
alpm_list_t *j;
pmpkg_t *local;
@@ -287,8 +281,8 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy
ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ STRDUP(targline, name, RET_ERR(PM_ERR_MEMORY, -1));
- strncpy(targline, name, PKG_FULLNAME_LEN);
targ = strchr(targline, '/');
if(targ) {
/* we are looking for a package in a specific database */
@@ -301,13 +295,15 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy
repo_found = 1;
spkg = _alpm_db_get_pkgfromcache(db, targ);
if(spkg == NULL) {
- RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
+ pm_errno = PM_ERR_PKG_NOT_FOUND;
+ goto error;
}
}
}
if(!repo_found) {
_alpm_log(PM_LOG_ERROR, _("repository '%s' not found\n"), targline);
- RET_ERR(PM_ERR_PKG_REPO_NOT_FOUND, -1);
+ pm_errno = PM_ERR_PKG_REPO_NOT_FOUND;
+ goto error;
}
} else {
targ = targline;
@@ -316,10 +312,16 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy
spkg = _alpm_db_get_pkgfromcache(db, targ);
}
if(spkg == NULL) {
- RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
+ pm_errno = PM_ERR_PKG_NOT_FOUND;
+ goto error;
}
}
+ if(_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) {
+ FREE(targline);
+ RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
+ }
+
if(_alpm_pkg_should_ignore(spkg)) {
int resp;
QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, spkg, NULL, NULL, &resp);
@@ -346,39 +348,80 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy
}
/* add the package to the transaction */
- if(!_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) {
- pmpkg_t *dummy = NULL;
- if(local) {
- dummy = _alpm_pkg_dup(local);
- if(dummy == NULL) {
- RET_ERR(PM_ERR_MEMORY, -1);
- }
- }
- sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, dummy);
- if(sync == NULL) {
- _alpm_pkg_free(dummy);
- RET_ERR(PM_ERR_MEMORY, -1);
- }
- _alpm_log(PM_LOG_DEBUG, "adding target '%s' to the transaction set\n",
- alpm_pkg_get_name(spkg));
- trans->packages = alpm_list_add(trans->packages, sync);
+ sync = _alpm_sync_new(PM_PKG_REASON_EXPLICIT, spkg, NULL);
+ if(sync == NULL) {
+ goto error;
}
+ _alpm_log(PM_LOG_DEBUG, "adding target '%s' to the transaction set\n",
+ alpm_pkg_get_name(spkg));
+ trans->packages = alpm_list_add(trans->packages, sync);
+ FREE(targline);
return(0);
+
+error:
+ if(targline) {
+ FREE(targline);
+ }
+ return(-1);
}
/* Helper functions for alpm_list_remove
- */
+*/
static int syncpkg_cmp(const void *s1, const void *s2)
{
const pmsyncpkg_t *sp1 = s1;
const pmsyncpkg_t *sp2 = s2;
- pmpkg_t *p1, *p2;
+ pmpkg_t *p1 = alpm_sync_get_pkg(sp1);
+ pmpkg_t *p2 = alpm_sync_get_pkg(sp2);
+ return(strcmp(alpm_pkg_get_name(p1), alpm_pkg_get_name(p2)));
+}
- p1 = alpm_sync_get_pkg(sp1);
- p2 = alpm_sync_get_pkg(sp2);
+/** Compute the size of the files that will be downloaded to install a
+ * package.
+ * @param newpkg the new package to upgrade to
+ */
+static int compute_download_size(pmpkg_t *newpkg)
+{
+ const char *fname;
+ char *fpath;
+ unsigned long size = 0;
- return(strcmp(alpm_pkg_get_name(p1), alpm_pkg_get_name(p2)));
+ fname = alpm_pkg_get_filename(newpkg);
+ ASSERT(fname != NULL, RET_ERR(PM_ERR_PKG_INVALID_NAME, -1));
+ fpath = _alpm_filecache_find(fname);
+
+ if(fpath) {
+ FREE(fpath);
+ size = 0;
+ } else if(handle->usedelta) {
+ unsigned long dltsize;
+ unsigned long pkgsize = alpm_pkg_get_size(newpkg);
+
+ dltsize = _alpm_shortest_delta_path(
+ alpm_pkg_get_deltas(newpkg),
+ alpm_pkg_get_filename(newpkg),
+ alpm_pkg_get_md5sum(newpkg),
+ &newpkg->delta_path);
+
+ if(newpkg->delta_path && (dltsize < pkgsize * MAX_DELTA_RATIO)) {
+ _alpm_log(PM_LOG_DEBUG, "using delta size\n");
+ size = dltsize;
+ } else {
+ _alpm_log(PM_LOG_DEBUG, "using package size\n");
+ size = alpm_pkg_get_size(newpkg);
+ alpm_list_free(newpkg->delta_path);
+ newpkg->delta_path = NULL;
+ }
+ } else {
+ size = alpm_pkg_get_size(newpkg);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "setting download size %ld for pkg %s\n", size,
+ alpm_pkg_get_name(newpkg));
+
+ newpkg->download_size = size;
+ return(0);
}
int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, alpm_list_t **data)
@@ -397,14 +440,15 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
*data = NULL;
}
- if(!(trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) {
- for(i = trans->packages; i; i = i->next) {
- pmsyncpkg_t *sync = i->data;
- list = alpm_list_add(list, sync->pkg);
- }
+ for(i = trans->packages; i; i = i->next) {
+ pmsyncpkg_t *sync = i->data;
+ list = alpm_list_add(list, sync->pkg);
}
if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
+ /* store a pointer to the last original target so we can tell what was
+ * pulled by resolvedeps */
+ alpm_list_t *pulled = alpm_list_last(list);
/* Resolve targets dependencies */
EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL);
_alpm_log(PM_LOG_DEBUG, "resolving target's dependencies\n");
@@ -412,10 +456,8 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
/* build remove list for resolvedeps */
for(i = trans->packages; i; i = i->next) {
pmsyncpkg_t *sync = i->data;
- if(sync->type == PM_SYNC_TYPE_REPLACE) {
- for(j = sync->data; j; j = j->next) {
- remove = alpm_list_add(remove, j->data);
- }
+ for(j = sync->removes; j; j = j->next) {
+ remove = alpm_list_add(remove, j->data);
}
}
@@ -429,33 +471,27 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
}
}
- if((trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) {
- FREELIST(trans->packages);
- }
-
- for(i = list; i; i = i->next) {
- /* add the dependencies found by resolvedeps to the transaction set */
+ for(i = pulled->next; i; i = i->next) {
pmpkg_t *spkg = i->data;
- if(!_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) {
- pmsyncpkg_t *sync = _alpm_sync_new(PM_SYNC_TYPE_DEPEND, spkg, NULL);
- if(sync == NULL) {
- ret = -1;
- goto cleanup;
- }
- trans->packages = alpm_list_add(trans->packages, sync);
- _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n",
- alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg));
+ pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_DEPEND, spkg, NULL);
+ if(sync == NULL) {
+ ret = -1;
+ goto cleanup;
}
+ trans->packages = alpm_list_add(trans->packages, sync);
+ _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n",
+ alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg));
}
/* re-order w.r.t. dependencies */
- alpm_list_t *sortlist = _alpm_sortbydeps(list, PM_TRANS_TYPE_ADD);
+ alpm_list_t *sortlist = _alpm_sortbydeps(list, 0);
alpm_list_t *newpkgs = NULL;
for(i = sortlist; i; i = i->next) {
for(j = trans->packages; j; j = j->next) {
pmsyncpkg_t *s = j->data;
if(s->pkg == i->data) {
newpkgs = alpm_list_add(newpkgs, s);
+ break;
}
}
}
@@ -472,180 +508,130 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
EVENT(trans, PM_TRANS_EVT_INTERCONFLICTS_START, NULL, NULL);
_alpm_log(PM_LOG_DEBUG, "looking for conflicts\n");
- deps = _alpm_checkconflicts(db_local, list);
- if(deps) {
- int errorout = 0;
- alpm_list_t *asked = NULL;
- pmconflict_t *conflict = NULL;
-
- for(i = deps; i && !errorout; i = i->next) {
- pmsyncpkg_t *sync;
- pmpkg_t *found = NULL;
-
- conflict = i->data;
- _alpm_log(PM_LOG_DEBUG, "package '%s' conflicts with '%s'\n",
- conflict->package1, conflict->package2);
- /* check if the conflicting package is about to be removed/replaced.
- * if so, then just ignore it. */
- for(j = trans->packages; j && !found; j = j->next) {
- sync = j->data;
- if(sync->type == PM_SYNC_TYPE_REPLACE) {
- found = _alpm_pkg_find(conflict->package2, sync->data);
- }
- }
- if(found) {
- _alpm_log(PM_LOG_DEBUG, "'%s' is already elected for removal -- skipping\n",
- alpm_pkg_get_name(found));
- continue;
- }
- sync = _alpm_sync_find(trans->packages, conflict->package1);
- if(sync == NULL) {
- _alpm_log(PM_LOG_DEBUG, "'%s' not found in transaction set -- skipping\n",
- conflict->package1);
- continue;
- }
- pmpkg_t *local = _alpm_db_get_pkgfromcache(db_local, conflict->package2);
- /* check if this package provides the package it's conflicting with */
- if(alpm_list_find(alpm_pkg_get_provides(sync->pkg),
- conflict->package2, _alpm_prov_cmp)) {
- /* treat like a replaces item so requiredby fields are
- * inherited properly. */
- _alpm_log(PM_LOG_DEBUG, "package '%s' provides its own conflict\n",
- conflict->package1);
- if(!local) {
- char *rmpkg = NULL;
- void *target, *depend;
- /* hmmm, package2 isn't installed, so it must be conflicting
- * with another package in our final list. For example:
- *
- * pacman -S blackbox xfree86
- *
- * If no x-servers are installed and blackbox pulls in xorg, then
- * xorg and xfree86 will conflict with each other. In this case,
- * we should follow the user's preference and rip xorg out of final,
- * opting for xfree86 instead.
- */
-
- /* figure out which one was requested in targets. If they both
- * were, then it's still an unresolvable conflict. */
- target = alpm_list_find_str(trans->targets, conflict->package1);
- depend = alpm_list_find_str(trans->targets, conflict->package2);
- if(depend && !target) {
- _alpm_log(PM_LOG_DEBUG, "'%s' is in the target list -- keeping it\n",
- conflict->package2);
- /* remove conflict->package1 */
- rmpkg = conflict->package1;
- } else if(target && !depend) {
- _alpm_log(PM_LOG_DEBUG, "'%s' is in the target list -- keeping it\n",
- conflict->package1);
- /* remove conflict->package2 */
- rmpkg = conflict->package2;
- } else {
- /* miss->target2 is not needed, miss->target already provides
- * it, let's resolve the conflict */
- rmpkg = conflict->package2;
- }
- if(rmpkg) {
- pmsyncpkg_t *rsync = _alpm_sync_find(trans->packages, rmpkg);
- if(rsync) {
- void *vpkg;
- _alpm_log(PM_LOG_DEBUG, "removing '%s' from target list\n",
- rsync->pkg->name);
- trans->packages = alpm_list_remove(trans->packages, rsync,
- syncpkg_cmp, &vpkg);
- _alpm_sync_free(vpkg);
- }
- continue;
- }
+ /* 1. check for conflicts in the target list */
+ _alpm_log(PM_LOG_DEBUG, "check targets vs targets\n");
+ deps = _alpm_innerconflicts(list);
+
+ for(i = deps; i; i = i->next) {
+ pmconflict_t *conflict = i->data;
+ pmsyncpkg_t *rsync, *sync, *sync1, *sync2;
+
+ /* have we already removed one of the conflicting targets? */
+ sync1 = _alpm_sync_find(trans->packages, conflict->package1);
+ sync2 = _alpm_sync_find(trans->packages, conflict->package2);
+ if(!sync1 || !sync2) {
+ continue;
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "conflicting packages in the sync list: '%s' <-> '%s'\n",
+ conflict->package1, conflict->package2);
+
+ /* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */
+ pmdepend_t *dep1 = _alpm_splitdep(conflict->package1);
+ pmdepend_t *dep2 = _alpm_splitdep(conflict->package2);
+ if(alpm_depcmp(sync1->pkg, dep2)) {
+ rsync = sync2;
+ sync = sync1;
+ } else if(alpm_depcmp(sync2->pkg, dep1)) {
+ rsync = sync1;
+ sync = sync2;
+ } else {
+ _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
+ pm_errno = PM_ERR_CONFLICTING_DEPS;
+ ret = -1;
+ if(data) {
+ pmconflict_t *newconflict = _alpm_conflict_dup(conflict);
+ if(newconflict) {
+ *data = alpm_list_add(*data, newconflict);
}
}
- /* It's a conflict -- see if they want to remove it */
- _alpm_log(PM_LOG_DEBUG, "resolving package '%s' conflict\n",
- conflict->package1);
- if(local) {
- int doremove = 0;
- if(!alpm_list_find_str(asked, conflict->package2)) {
- QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, conflict->package1,
- conflict->package2, NULL, &doremove);
- asked = alpm_list_add(asked, strdup(conflict->package2));
- if(doremove) {
- pmpkg_t *q = _alpm_pkg_dup(local);
- if(sync->type != PM_SYNC_TYPE_REPLACE) {
- /* switch this sync type to REPLACE */
- sync->type = PM_SYNC_TYPE_REPLACE;
- _alpm_pkg_free(sync->data);
- sync->data = NULL;
- }
- /* append to the replaces list */
- _alpm_log(PM_LOG_DEBUG, "electing '%s' for removal\n",
- conflict->package2);
- sync->data = alpm_list_add(sync->data, q);
- /* see if the package is in the current target list */
- pmsyncpkg_t *rsync = _alpm_sync_find(trans->packages,
- conflict->package2);
- if(rsync) {
- /* remove it from the target list */
- void *vpkg;
- _alpm_log(PM_LOG_DEBUG, "removing '%s' from target list\n",
- conflict->package2);
- trans->packages = alpm_list_remove(trans->packages, rsync,
- syncpkg_cmp, &vpkg);
- _alpm_sync_free(vpkg);
- }
- } else {
- /* abort */
- _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
- errorout = 1;
- }
- }
- } else {
- _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
- errorout = 1;
+ alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
+ alpm_list_free(deps);
+ _alpm_dep_free(dep1);
+ _alpm_dep_free(dep2);
+ goto cleanup;
+ }
+ _alpm_dep_free(dep1);
+ _alpm_dep_free(dep2);
+
+ /* Prints warning */
+ _alpm_log(PM_LOG_WARNING,
+ _("removing '%s' from target list because it conflicts with '%s'\n"),
+ rsync->pkg->name, sync->pkg->name);
+ void *vpkg;
+ trans->packages = alpm_list_remove(trans->packages, rsync,
+ syncpkg_cmp, &vpkg);
+ pmsyncpkg_t *syncpkg = vpkg;
+ list = alpm_list_remove(list, syncpkg->pkg, _alpm_pkg_cmp, NULL);
+ _alpm_sync_free(syncpkg);
+ continue;
+ }
+
+ alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
+ alpm_list_free(deps);
+ deps = NULL;
+
+ /* 2. we check for target vs db conflicts (and resolve)*/
+ _alpm_log(PM_LOG_DEBUG, "check targets vs db and db vs targets\n");
+ deps = _alpm_outerconflicts(db_local, list);
+
+ for(i = deps; i; i = i->next) {
+ pmconflict_t *conflict = i->data;
+
+ /* if conflict->package2 (the local package) is not elected for removal,
+ we ask the user */
+ int found = 0;
+ for(j = trans->packages; j && !found; j = j->next) {
+ pmsyncpkg_t *sync = j->data;
+ if(_alpm_pkg_find(sync->removes, conflict->package2)) {
+ found = 1;
}
}
- if(errorout) {
- /* The last conflict was unresolvable, so we duplicate it and add it to *data */
+ if(found) {
+ continue;
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "package '%s' conflicts with '%s'\n",
+ conflict->package1, conflict->package2);
+
+ pmsyncpkg_t *sync = _alpm_sync_find(trans->packages, conflict->package1);
+ pmpkg_t *local = _alpm_db_get_pkgfromcache(db_local, conflict->package2);
+ int doremove = 0;
+ QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, conflict->package1,
+ conflict->package2, NULL, &doremove);
+ if(doremove) {
+ /* append to the removes list */
+ _alpm_log(PM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2);
+ sync->removes = alpm_list_add(sync->removes, local);
+ } else { /* abort */
+ _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
pm_errno = PM_ERR_CONFLICTING_DEPS;
+ ret = -1;
if(data) {
- pmconflict_t *lastconflict = conflict;
- if((conflict = malloc(sizeof(pmconflict_t))) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %zd bytes\n"),
- sizeof(pmconflict_t));
- FREELIST(*data);
- pm_errno = PM_ERR_MEMORY;
- } else {
- *conflict = *lastconflict;
- *data = alpm_list_add(*data, conflict);
+ pmconflict_t *newconflict = _alpm_conflict_dup(conflict);
+ if(newconflict) {
+ *data = alpm_list_add(*data, newconflict);
}
}
- FREELIST(asked);
- FREELIST(deps);
- ret = -1;
+ alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
+ alpm_list_free(deps);
goto cleanup;
}
- FREELIST(asked);
- FREELIST(deps);
}
EVENT(trans, PM_TRANS_EVT_INTERCONFLICTS_DONE, NULL, NULL);
+ alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
+ alpm_list_free(deps);
}
if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
- /* rebuild remove and list */
- alpm_list_free(list);
- list = NULL;
- for(i = trans->packages; i; i = i->next) {
- pmsyncpkg_t *sync = i->data;
- list = alpm_list_add(list, sync->pkg);
- }
+ /* rebuild remove list */
alpm_list_free(remove);
remove = NULL;
for(i = trans->packages; i; i = i->next) {
pmsyncpkg_t *sync = i->data;
- if(sync->type == PM_SYNC_TYPE_REPLACE) {
- for(j = sync->data; j; j = j->next) {
- remove = alpm_list_add(remove, j->data);
- }
+ for(j = sync->removes; j; j = j->next) {
+ remove = alpm_list_add(remove, j->data);
}
}
@@ -657,11 +643,20 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
if(data) {
*data = deps;
} else {
- FREELIST(deps);
+ alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
+ alpm_list_free(deps);
}
goto cleanup;
}
}
+ for(i = list; i; i = i->next) {
+ /* update download size field */
+ pmpkg_t *spkg = i->data;
+ if(compute_download_size(spkg) != 0) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
cleanup:
alpm_list_free(list);
@@ -670,86 +665,14 @@ cleanup:
return(ret);
}
-/** Returns a list of deltas that should be downloaded instead of the
- * package.
- *
- * It first tests if a delta path exists between the currently installed
- * version (if any) and the version to upgrade to. If so, the delta path
- * is used if its size is below a set percentage (MAX_DELTA_RATIO) of
- * the package size, Otherwise, an empty list is returned.
- *
- * @param newpkg the new package to upgrade to
- * @param db_local the local database
- *
- * @return the list of pmdelta_t * objects. NULL (the empty list) is
- * returned if the package should be downloaded instead of deltas.
- */
-static alpm_list_t *pkg_upgrade_delta_path(pmpkg_t *newpkg, pmdb_t *db_local)
-{
- pmpkg_t *oldpkg = alpm_db_get_pkg(db_local, newpkg->name);
- alpm_list_t *ret = NULL;
-
- if(oldpkg) {
- const char *oldname = alpm_pkg_get_filename(oldpkg);
- char *oldpath = _alpm_filecache_find(oldname);
-
- if(oldpath) {
- alpm_list_t *deltas = _alpm_shortest_delta_path(
- alpm_pkg_get_deltas(newpkg),
- alpm_pkg_get_version(oldpkg),
- alpm_pkg_get_version(newpkg));
-
- if(deltas) {
- unsigned long dltsize = _alpm_delta_path_size(deltas);
- unsigned long pkgsize = alpm_pkg_get_size(newpkg);
-
- if(dltsize < pkgsize * MAX_DELTA_RATIO) {
- ret = deltas;
- } else {
- ret = NULL;
- alpm_list_free(deltas);
- }
- }
-
- FREE(oldpath);
- }
- }
-
- return(ret);
-}
-
/** Returns the size of the files that will be downloaded to install a
* package.
- *
* @param newpkg the new package to upgrade to
- * @param db_local the local database
- *
* @return the size of the download
*/
-unsigned long SYMEXPORT alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local)
+unsigned long SYMEXPORT alpm_pkg_download_size(pmpkg_t *newpkg)
{
- char *fpath = _alpm_filecache_find(alpm_pkg_get_filename(newpkg));
- unsigned long size = 0;
-
- if(fpath) {
- size = 0;
- } else if(handle->usedelta) {
- alpm_list_t *deltas = pkg_upgrade_delta_path(newpkg, db_local);
-
- if(deltas) {
- size = _alpm_delta_path_size_uncached(deltas);
- } else {
- size = alpm_pkg_get_size(newpkg);
- }
-
- alpm_list_free(deltas);
- } else {
- size = alpm_pkg_get_size(newpkg);
- }
-
- FREE(fpath);
-
- return(size);
+ return(newpkg->download_size);
}
/** Applies delta files to create an upgraded package file.
@@ -758,88 +681,82 @@ unsigned long SYMEXPORT alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local
* ending package files.
*
* @param trans the transaction
- * @param patches A list of alternating pmpkg_t * and pmdelta_t *
- * objects. The patch command will be built using the pmpkg_t, pmdelta_t
- * pair.
*
* @return 0 if all delta files were able to be applied, 1 otherwise.
*/
-static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches)
+static int apply_deltas(pmtrans_t *trans)
{
- /* keep track of the previous package in the loop to decide if a
- * package file should be deleted */
- pmpkg_t *lastpkg = NULL;
- int lastpkg_failed = 0;
+ alpm_list_t *i;
int ret = 0;
const char *cachedir = _alpm_filecache_setup();
- alpm_list_t *p = patches;
- while(p) {
- pmpkg_t *pkg;
- pmdelta_t *d;
- char command[PATH_MAX], fname[PATH_MAX];
- char pkgfilename[PKG_FILENAME_LEN];
+ for(i = trans->packages; i; i = i->next) {
+ pmsyncpkg_t *sync = i->data;
+ pmpkg_t *spkg = sync->pkg;
+ alpm_list_t *delta_path = spkg->delta_path;
+ alpm_list_t *dlts = NULL;
- pkg = alpm_list_getdata(p);
- p = alpm_list_next(p);
+ if(!delta_path) {
+ continue;
+ }
- d = alpm_list_getdata(p);
- p = alpm_list_next(p);
+ for(dlts = delta_path; dlts; dlts = dlts->next) {
+ pmdelta_t *d = dlts->data;
+ char *delta, *from, *to;
+ char command[PATH_MAX];
+ int len = 0;
- /* if patching fails, ignore the rest of that package's deltas */
- if(lastpkg_failed) {
- if(pkg == lastpkg) {
- continue;
+ delta = _alpm_filecache_find(d->delta);
+ /* the initial package might be in a different cachedir */
+ if(dlts == delta_path) {
+ from = _alpm_filecache_find(d->from);
} else {
- lastpkg_failed = 0;
+ /* len = cachedir len + from len + '/' + null */
+ len = strlen(cachedir) + strlen(d->from) + 2;
+ CALLOC(from, len, sizeof(char), RET_ERR(PM_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(PM_ERR_MEMORY, 1));
+ snprintf(to, len, "%s/%s", cachedir, d->to);
- /* an example of the patch command: (using /cache for cachedir)
- * xdelta patch /cache/pacman_3.0.0-1_to_3.0.1-1-i686.delta \
- * /cache/pacman-3.0.0-1-i686.pkg.tar.gz \
- * /cache/pacman-3.0.1-1-i686.pkg.tar.gz
- */
-
- /* build the patch command */
- snprintf(command, PATH_MAX,
- "xdelta patch" /* the command */
- " %s/%s" /* the delta */
- " %s/%s-%s-%s" PKGEXT /* the 'from' package */
- " %s/%s-%s-%s" PKGEXT, /* the 'to' package */
- cachedir, d->filename,
- cachedir, pkg->name, d->from, pkg->arch,
- cachedir, pkg->name, d->to, pkg->arch);
-
- _alpm_log(PM_LOG_DEBUG, _("command: %s\n"), command);
-
- snprintf(pkgfilename, PKG_FILENAME_LEN, "%s-%s-%s" PKGEXT,
- pkg->name, d->to, pkg->arch);
-
- EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_START, pkgfilename, d->filename);
-
- if(system(command) == 0) {
- EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_DONE, NULL, NULL);
-
- /* delete the delta file */
- snprintf(fname, PATH_MAX, "%s/%s", cachedir, d->filename);
- unlink(fname);
-
- /* Delete the 'from' package but only if it is an intermediate
- * package. The starting 'from' package should be kept, just
- * as if deltas were not used. Delete the package file if the
- * previous iteration of the loop used the same package. */
- if(pkg == lastpkg) {
- snprintf(fname, PATH_MAX, "%s/%s-%s-%s" PKGEXT,
- cachedir, pkg->name, d->from, pkg->arch);
- unlink(fname);
- } else {
- lastpkg = pkg;
+ /* an example of the patch command: (using /cache for cachedir)
+ * xdelta patch /path/to/pacman_3.0.0-1_to_3.0.1-1-i686.delta \
+ * /path/to/pacman-3.0.0-1-i686.pkg.tar.gz \
+ * /cache/pacman-3.0.1-1-i686.pkg.tar.gz
+ */
+
+ /* build the patch command */
+ snprintf(command, PATH_MAX, "xdelta patch %s %s %s", delta, from, to);
+
+ _alpm_log(PM_LOG_DEBUG, _("command: %s\n"), command);
+
+ EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_START, d->to, d->delta);
+
+ int retval = system(command);
+ if(retval == 0) {
+ EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_DONE, NULL, NULL);
+
+ /* delete the delta file */
+ unlink(delta);
+
+ /* Delete the 'from' package but only if it is an intermediate
+ * package. The starting 'from' package should be kept, just
+ * as if deltas were not used. */
+ if(dlts != delta_path) {
+ unlink(from);
+ }
+ }
+ FREE(from);
+ FREE(to);
+ FREE(delta);
+
+ if(retval != 0) {
+ /* one delta failed for this package, cancel the remaining ones */
+ EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL);
+ ret = 1;
+ break;
}
- } else {
- EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL);
- lastpkg_failed = 1;
- ret = 1;
}
}
@@ -854,107 +771,29 @@ static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches)
* @param trans the transaction
* @param filename the filename of the file to test
* @param md5sum the expected md5sum of the file
- * @param data data to write the error messages to
*
- * @return 0 if the md5sum matched, 1 otherwise
+ * @return 0 if the md5sum matched, 1 if not, -1 in case of errors
*/
static int test_md5sum(pmtrans_t *trans, const char *filename,
- const char *md5sum, alpm_list_t **data)
+ const char *md5sum)
{
char *filepath;
- char *md5sum2;
- char *errormsg = NULL;
- int ret = 0;
+ int ret;
filepath = _alpm_filecache_find(filename);
- md5sum2 = alpm_get_md5sum(filepath);
- if(md5sum == NULL) {
- if(data) {
- /* TODO wtf is this? malloc'd strings for error messages? */
- if((errormsg = calloc(512, sizeof(char))) == NULL) {
- RET_ERR(PM_ERR_MEMORY, -1);
- }
- snprintf(errormsg, 512, _("can't get md5 checksum for file %s\n"),
- filename);
- *data = alpm_list_add(*data, errormsg);
- }
- ret = 1;
- } else if(md5sum2 == NULL) {
- if(data) {
- if((errormsg = calloc(512, sizeof(char))) == NULL) {
- RET_ERR(PM_ERR_MEMORY, -1);
- }
- snprintf(errormsg, 512, _("can't get md5 checksum for file %s\n"),
- filename);
- *data = alpm_list_add(*data, errormsg);
- }
- ret = 1;
- } else if(strcmp(md5sum, md5sum2) != 0) {
+ ret = _alpm_test_md5sum(filepath, md5sum);
+
+ if(ret == 1) {
int doremove = 0;
QUESTION(trans, PM_TRANS_CONV_CORRUPTED_PKG, (char *)filename,
NULL, NULL, &doremove);
if(doremove) {
unlink(filepath);
}
- if(data) {
- if((errormsg = calloc(512, sizeof(char))) == NULL) {
- RET_ERR(PM_ERR_MEMORY, -1);
- }
- snprintf(errormsg, 512, _("file %s was corrupted (bad MD5 checksum)\n"),
- filename);
- *data = alpm_list_add(*data, errormsg);
- }
- ret = 1;
}
FREE(filepath);
- FREE(md5sum2);
-
- return(ret);
-}
-
-/** Compares the md5sum of a delta to the expected value.
- *
- * @param trans the transaction
- * @param delta the delta to test
- * @param data data to write the error messages to
- *
- * @return 0 if the md5sum matched, 1 otherwise
- */
-static int test_delta_md5sum(pmtrans_t *trans, pmdelta_t *delta,
- alpm_list_t **data)
-{
- const char *filename;
- const char *md5sum;
- int ret = 0;
-
- filename = alpm_delta_get_filename(delta);
- md5sum = alpm_delta_get_md5sum(delta);
-
- ret = test_md5sum(trans, filename, md5sum, data);
-
- return(ret);
-}
-
-/** Compares the md5sum of a package to the expected value.
- *
- * @param trans the transaction
- * @param pkg the package to test
- * @param data data to write the error messages to
- *
- * @return 0 if the md5sum matched, 1 otherwise
- */
-static int test_pkg_md5sum(pmtrans_t *trans, pmpkg_t *pkg, alpm_list_t **data)
-{
- const char *filename;
- const char *md5sum;
- int ret = 0;
-
- filename = alpm_pkg_get_filename(pkg);
- md5sum = alpm_pkg_get_md5sum(pkg);
-
- ret = test_md5sum(trans, filename, md5sum, data);
return(ret);
}
@@ -962,11 +801,12 @@ static int test_pkg_md5sum(pmtrans_t *trans, pmpkg_t *pkg, alpm_list_t **data)
int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
{
alpm_list_t *i, *j, *files = NULL;
- alpm_list_t *patches = NULL, *deltas = NULL;
+ alpm_list_t *deltas = NULL;
pmtrans_t *tr = NULL;
- int replaces = 0, retval = 0;
+ int replaces = 0;
+ int errors = 0;
const char *cachedir = NULL;
- int dltotal = 0, dl = 0;
+ int ret = -1;
ALPM_LOG_FUNC;
@@ -976,14 +816,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
cachedir = _alpm_filecache_setup();
trans->state = STATE_DOWNLOADING;
- /* Sum up the download sizes. This has to be in its own loop because
- * the download loop is grouped by db. */
- for(j = trans->packages; j; j = j->next) {
- pmsyncpkg_t *sync = j->data;
- pmpkg_t *spkg = sync->pkg;
- dltotal += alpm_pkg_download_size(spkg, db_local);
- }
-
/* group sync records by repository and download */
for(i = handle->dbs_sync; i; i = i->next) {
pmdb_t *current = i->data;
@@ -997,60 +829,45 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
const char *fname = NULL;
fname = alpm_pkg_get_filename(spkg);
+ ASSERT(fname != NULL, RET_ERR(PM_ERR_PKG_INVALID_NAME, -1));
if(trans->flags & PM_TRANS_FLAG_PRINTURIS) {
EVENT(trans, PM_TRANS_EVT_PRINTURI, (char *)alpm_db_get_url(current),
(char *)fname);
} else {
- char *fpath = _alpm_filecache_find(fname);
- if(!fpath) {
- if(handle->usedelta) {
- alpm_list_t *delta_path = pkg_upgrade_delta_path(spkg, db_local);
-
- if(delta_path) {
- alpm_list_t *dlts = NULL;
-
- for(dlts = delta_path; dlts; dlts = alpm_list_next(dlts)) {
- pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts);
- char *fpath2 = _alpm_filecache_find(d->filename);
-
- if(!fpath2) {
- /* add the delta filename to the download list if
- * it's not in the cache*/
- files = alpm_list_add(files, strdup(d->filename));
- }
-
- /* save the package and delta so that the xdelta patch
- * command can be run after the downloads finish */
- patches = alpm_list_add(patches, spkg);
- patches = alpm_list_add(patches, d);
-
- /* keep a list of the delta files for md5sums */
- deltas = alpm_list_add(deltas, d);
+ if(spkg->download_size != 0) {
+ alpm_list_t *delta_path = spkg->delta_path;
+ if(delta_path) {
+ alpm_list_t *dlts = NULL;
+
+ for(dlts = delta_path; dlts; dlts = dlts->next) {
+ pmdelta_t *d = dlts->data;
+
+ if(d->download_size != 0) {
+ /* add the delta filename to the download list if
+ * it's not in the cache */
+ files = alpm_list_add(files, strdup(d->delta));
}
- alpm_list_free(delta_path);
- delta_path = NULL;
- } else {
- /* no deltas to download, so add the file to the
- * download list */
- files = alpm_list_add(files, strdup(fname));
+ /* keep a list of the delta files for md5sums */
+ deltas = alpm_list_add(deltas, d);
}
+
} else {
/* not using deltas, so add the file to the download list */
files = alpm_list_add(files, strdup(fname));
}
}
- FREE(fpath);
}
}
}
if(files) {
EVENT(trans, PM_TRANS_EVT_RETRIEVE_START, current->treename, NULL);
- if(_alpm_downloadfiles(current->servers, cachedir, files, &dl, dltotal)) {
+ if(_alpm_download_files(files, current->servers, cachedir)) {
_alpm_log(PM_LOG_WARNING, _("failed to retrieve some files from %s\n"),
current->treename);
- RET_ERR(PM_ERR_RETRIEVE, -1);
+ pm_errno = PM_ERR_RETRIEVE;
+ goto error;
}
FREELIST(files);
}
@@ -1064,35 +881,31 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
/* only output if there are deltas to work with */
if(deltas) {
+ errors = 0;
/* Check integrity of deltas */
EVENT(trans, PM_TRANS_EVT_DELTA_INTEGRITY_START, NULL, NULL);
for(i = deltas; i; i = i->next) {
pmdelta_t *d = alpm_list_getdata(i);
+ const char *filename = alpm_delta_get_filename(d);
+ const char *md5sum = alpm_delta_get_md5sum(d);
- ret = test_delta_md5sum(trans, d, data);
-
- if(ret == 1) {
- retval = 1;
- } else if(ret == -1) { /* -1 is for serious errors */
- RET_ERR(pm_errno, -1);
+ if(test_md5sum(trans, filename, md5sum) != 0) {
+ errors++;
+ *data = alpm_list_add(*data, strdup(filename));
}
}
- if(retval) {
- pm_errno = PM_ERR_DLT_CORRUPTED;
+ if(errors) {
+ pm_errno = PM_ERR_DLT_INVALID;
goto error;
}
EVENT(trans, PM_TRANS_EVT_DELTA_INTEGRITY_DONE, NULL, NULL);
/* Use the deltas to generate the packages */
EVENT(trans, PM_TRANS_EVT_DELTA_PATCHES_START, NULL, NULL);
- ret = apply_deltas(trans, patches);
+ ret = apply_deltas(trans);
EVENT(trans, PM_TRANS_EVT_DELTA_PATCHES_DONE, NULL, NULL);
- alpm_list_free(patches);
- patches = NULL;
- alpm_list_free(deltas);
- deltas = NULL;
}
if(ret) {
pm_errno = PM_ERR_DLT_PATCHFAILED;
@@ -1103,21 +916,20 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
/* Check integrity of packages */
EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL);
+ errors = 0;
for(i = trans->packages; i; i = i->next) {
pmsyncpkg_t *sync = i->data;
pmpkg_t *spkg = sync->pkg;
- int ret = 0;
+ const char *filename = alpm_pkg_get_filename(spkg);
+ const char *md5sum = alpm_pkg_get_md5sum(spkg);
- ret = test_pkg_md5sum(trans, spkg, data);
-
- if(ret == 1) {
- retval = 1;
- } else if(ret == -1) { /* -1 is for serious errors */
- RET_ERR(pm_errno, -1);
+ if(test_md5sum(trans, filename, md5sum) != 0) {
+ errors++;
+ *data = alpm_list_add(*data, strdup(filename));
}
}
- if(retval) {
- pm_errno = PM_ERR_PKG_CORRUPTED;
+ if(errors) {
+ pm_errno = PM_ERR_PKG_INVALID;
goto error;
}
EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL);
@@ -1130,7 +942,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
tr = _alpm_trans_new();
if(tr == NULL) {
_alpm_log(PM_LOG_ERROR, _("could not create removal transaction\n"));
- pm_errno = PM_ERR_MEMORY;
goto error;
}
@@ -1141,16 +952,14 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
for(i = trans->packages; i; i = i->next) {
pmsyncpkg_t *sync = i->data;
- if(sync->type == PM_SYNC_TYPE_REPLACE) {
- alpm_list_t *j;
- for(j = sync->data; j; j = j->next) {
- pmpkg_t *pkg = j->data;
- if(!_alpm_pkg_find(pkg->name, tr->packages)) {
- if(_alpm_trans_addtarget(tr, pkg->name) == -1) {
- goto error;
- }
- replaces++;
+ alpm_list_t *j;
+ for(j = sync->removes; j; j = j->next) {
+ pmpkg_t *pkg = j->data;
+ if(!_alpm_pkg_find(tr->packages, pkg->name)) {
+ if(_alpm_trans_addtarget(tr, pkg->name) == -1) {
+ goto error;
}
+ replaces++;
}
}
}
@@ -1175,7 +984,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
tr = _alpm_trans_new();
if(tr == NULL) {
_alpm_log(PM_LOG_ERROR, _("could not create transaction\n"));
- pm_errno = PM_ERR_MEMORY;
goto error;
}
if(_alpm_trans_init(tr, PM_TRANS_TYPE_UPGRADE, trans->flags | PM_TRANS_FLAG_NODEPS, trans->cb_event, trans->cb_conv, trans->cb_progress) == -1) {
@@ -1189,6 +997,9 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
char *fpath;
fname = alpm_pkg_get_filename(spkg);
+ if(fname == NULL) {
+ goto error;
+ }
/* Loop through the cache dirs until we find a matching file */
fpath = _alpm_filecache_find(fname);
@@ -1201,9 +1012,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
/* using alpm_list_last() is ok because addtarget() adds the new target at the
* end of the tr->packages list */
spkg = alpm_list_last(tr->packages)->data;
- if(sync->type == PM_SYNC_TYPE_DEPEND) {
- spkg->reason = PM_PKG_REASON_DEPEND;
- }
+ spkg->reason = sync->newreason;
}
if(_alpm_trans_prepare(tr, data) == -1) {
_alpm_log(PM_LOG_ERROR, _("could not prepare transaction\n"));
@@ -1214,15 +1023,15 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
_alpm_log(PM_LOG_ERROR, _("could not commit transaction\n"));
goto error;
}
- _alpm_trans_free(tr);
- tr = NULL;
-
- return(0);
+ ret = 0;
error:
+ FREELIST(files);
+ alpm_list_free(deltas);
+ deltas = NULL;
_alpm_trans_free(tr);
tr = NULL;
- return(-1);
+ return(ret);
}
pmsyncpkg_t *_alpm_sync_find(alpm_list_t *syncpkgs, const char* pkgname)
@@ -1246,14 +1055,6 @@ pmsyncpkg_t *_alpm_sync_find(alpm_list_t *syncpkgs, const char* pkgname)
return(NULL); /* not found */
}
-pmsynctype_t SYMEXPORT alpm_sync_get_type(const pmsyncpkg_t *sync)
-{
- /* Sanity checks */
- ASSERT(sync != NULL, return(-1));
-
- return sync->type;
-}
-
pmpkg_t SYMEXPORT *alpm_sync_get_pkg(const pmsyncpkg_t *sync)
{
/* Sanity checks */
@@ -1262,12 +1063,12 @@ pmpkg_t SYMEXPORT *alpm_sync_get_pkg(const pmsyncpkg_t *sync)
return sync->pkg;
}
-void SYMEXPORT *alpm_sync_get_data(const pmsyncpkg_t *sync)
+alpm_list_t SYMEXPORT *alpm_sync_get_removes(const pmsyncpkg_t *sync)
{
/* Sanity checks */
ASSERT(sync != NULL, return(NULL));
- return sync->data;
+ return sync->removes;
}
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/sync.h b/lib/libalpm/sync.h
index a6a3e74f..b71f0ef2 100644
--- a/lib/libalpm/sync.h
+++ b/lib/libalpm/sync.h
@@ -25,12 +25,12 @@
/* Sync package */
struct __pmsyncpkg_t {
- pmsynctype_t type;
+ pmpkgreason_t newreason;
pmpkg_t *pkg;
- void *data;
+ alpm_list_t *removes;
};
-pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data);
+pmsyncpkg_t *_alpm_sync_new(pmpkgreason_t newreason, pmpkg_t *spkg, alpm_list_t *removes);
void _alpm_sync_free(pmsyncpkg_t *data);
int _alpm_sync_sysupgrade(pmtrans_t *trans,
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index ecc40a0f..eb53e952 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -35,7 +35,6 @@
/* libalpm */
#include "trans.h"
#include "alpm_list.h"
-#include "error.h"
#include "package.h"
#include "util.h"
#include "log.h"
@@ -228,7 +227,6 @@ pmtrans_t *_alpm_trans_new()
CALLOC(trans, 1, sizeof(pmtrans_t), RET_ERR(PM_ERR_MEMORY, NULL));
- trans->targets = NULL;
trans->packages = NULL;
trans->skip_add = NULL;
trans->skip_remove = NULL;
@@ -250,10 +248,10 @@ void _alpm_trans_free(pmtrans_t *trans)
return;
}
- FREELIST(trans->targets);
if(trans->type == PM_TRANS_TYPE_SYNC) {
alpm_list_free_inner(trans->packages, (alpm_list_fn_free)_alpm_sync_free);
- } else {
+ } else if (trans->type == PM_TRANS_TYPE_REMOVE ||
+ trans->type == PM_TRANS_TYPE_REMOVEUPGRADE) {
alpm_list_free_inner(trans->packages, (alpm_list_fn_free)_alpm_pkg_free);
}
alpm_list_free(trans->packages);
@@ -307,13 +305,7 @@ int _alpm_trans_addtarget(pmtrans_t *trans, char *target)
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(target != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
- if(alpm_list_find_str(trans->targets, target)) {
- return(0);
- //RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
- }
-
switch(trans->type) {
- case PM_TRANS_TYPE_ADD:
case PM_TRANS_TYPE_UPGRADE:
if(_alpm_add_loadtarget(trans, handle->db_local, target) == -1) {
/* pm_errno is set by _alpm_add_loadtarget() */
@@ -335,8 +327,6 @@ int _alpm_trans_addtarget(pmtrans_t *trans, char *target)
break;
}
- trans->targets = alpm_list_add(trans->targets, strdup(target));
-
return(0);
}
@@ -357,7 +347,6 @@ int _alpm_trans_prepare(pmtrans_t *trans, alpm_list_t **data)
}
switch(trans->type) {
- case PM_TRANS_TYPE_ADD:
case PM_TRANS_TYPE_UPGRADE:
if(_alpm_add_prepare(trans, handle->db_local, data) == -1) {
/* pm_errno is set by _alpm_add_prepare() */
@@ -402,7 +391,6 @@ int _alpm_trans_commit(pmtrans_t *trans, alpm_list_t **data)
trans->state = STATE_COMMITING;
switch(trans->type) {
- case PM_TRANS_TYPE_ADD:
case PM_TRANS_TYPE_UPGRADE:
if(_alpm_add_commit(trans, handle->db_local) == -1) {
/* pm_errno is set by _alpm_add_commit() */
@@ -636,15 +624,6 @@ unsigned int SYMEXPORT alpm_trans_get_flags()
return handle->trans->flags;
}
-alpm_list_t SYMEXPORT * alpm_trans_get_targets()
-{
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(handle->trans != NULL, return(NULL));
-
- return handle->trans->targets;
-}
-
alpm_list_t SYMEXPORT * alpm_trans_get_pkgs()
{
/* Sanity checks */
diff --git a/lib/libalpm/trans.h b/lib/libalpm/trans.h
index 75608ce4..d74c3e90 100644
--- a/lib/libalpm/trans.h
+++ b/lib/libalpm/trans.h
@@ -39,7 +39,6 @@ struct __pmtrans_t {
pmtranstype_t type;
pmtransflag_t flags;
pmtransstate_t state;
- alpm_list_t *targets; /* list of (char *) */
alpm_list_t *packages; /* list of (pmpkg_t *) or (pmsyncpkg_t *) */
alpm_list_t *skip_add; /* list of (char *) */
alpm_list_t *skip_remove; /* list of (char *) */
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index e1413a25..55bd46a8 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -43,7 +43,6 @@
/* libalpm */
#include "util.h"
#include "log.h"
-#include "error.h"
#include "package.h"
#include "alpm.h"
#include "alpm_list.h"
@@ -186,57 +185,65 @@ int _alpm_makepath(const char *path)
/* does the same thing as 'mkdir -p' */
int _alpm_makepath_mode(const char *path, mode_t mode)
{
- char *orig, *str, *ptr;
- char full[PATH_MAX] = "";
- mode_t oldmask;
-
- oldmask = umask(0000);
+ /* A bit of pointer hell here. Descriptions:
+ * orig - a copy of path so we can safely butcher it with strsep
+ * str - the current position in the path string (after the delimiter)
+ * ptr - the original position of str after calling strsep
+ * incr - incrementally generated path for use in stat/mkdir call
+ */
+ char *orig, *str, *ptr, *incr;
+ mode_t oldmask = umask(0000);
+ int ret = 0;
orig = strdup(path);
+ incr = calloc(strlen(orig) + 1, sizeof(char));
str = orig;
while((ptr = strsep(&str, "/"))) {
if(strlen(ptr)) {
struct stat buf;
-
- strcat(full, "/");
- strcat(full, ptr);
- if(stat(full, &buf)) {
- if(mkdir(full, mode)) {
- FREE(orig);
- umask(oldmask);
- _alpm_log(PM_LOG_ERROR, _("failed to make path '%s' : %s\n"),
- path, strerror(errno));
- return(1);
+ /* we have another path component- append the newest component to
+ * existing string and create one more level of dir structure */
+ strcat(incr, "/");
+ strcat(incr, ptr);
+ if(stat(incr, &buf)) {
+ if(mkdir(incr, mode)) {
+ ret = 1;
+ break;
}
}
}
}
- FREE(orig);
+ free(orig);
+ free(incr);
umask(oldmask);
- return(0);
+ return(ret);
}
+#define CPBUFSIZE 8 * 1024
+
int _alpm_copyfile(const char *src, const char *dest)
{
FILE *in, *out;
size_t len;
- char buf[4097];
+ char *buf;
+ int ret = 0;
- in = fopen(src, "r");
+ in = fopen(src, "rb");
if(in == NULL) {
return(1);
}
- out = fopen(dest, "w");
+ out = fopen(dest, "wb");
if(out == NULL) {
fclose(in);
return(1);
}
+ CALLOC(buf, (size_t)CPBUFSIZE, (size_t)1, ret = 1; goto cleanup;);
+
/* do the actual file copy */
- while((len = fread(buf, 1, 4096, in))) {
+ while((len = fread(buf, 1, CPBUFSIZE, in))) {
fwrite(buf, 1, len, out);
}
- fclose(in);
/* chmod dest to permissions of src, as long as it is not a symlink */
struct stat statbuf;
@@ -246,12 +253,14 @@ int _alpm_copyfile(const char *src, const char *dest)
}
} else {
/* stat was unsuccessful */
- fclose(out);
- return(1);
+ ret = 1;
}
+cleanup:
+ fclose(in);
fclose(out);
- return(0);
+ FREE(buf);
+ return(ret);
}
/* Trim whitespace and newlines from a string
@@ -371,6 +380,13 @@ int _alpm_lckrm()
/* Compression functions */
+/**
+ * @brief Unpack a specific file or all files in an archive.
+ *
+ * @param archive the archive to unpack
+ * @param prefix where to extract the files
+ * @param fn a file within the archive to unpack or NULL for all
+ */
int _alpm_unpack(const char *archive, const char *prefix, const char *fn)
{
int ret = 1;
@@ -382,7 +398,7 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn)
ALPM_LOG_FUNC;
if((_archive = archive_read_new()) == NULL)
- RET_ERR(PM_ERR_LIBARCHIVE_ERROR, -1);
+ RET_ERR(PM_ERR_LIBARCHIVE, -1);
archive_read_support_compression_all(_archive);
archive_read_support_format_all(_archive);
@@ -408,13 +424,17 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn)
archive_entry_set_mode(entry, 0755);
}
+ /* If a specific file was requested skip entries that don't match. */
if (fn && strcmp(fn, entryname)) {
+ _alpm_log(PM_LOG_DEBUG, "skipping: %s\n", entryname);
if (archive_read_data_skip(_archive) != ARCHIVE_OK) {
ret = 1;
goto cleanup;
}
continue;
}
+
+ /* Extract the archive entry. */
ret = 0;
snprintf(expath, PATH_MAX, "%s/%s", prefix, entryname);
archive_entry_set_pathname(entry, expath);
@@ -535,8 +555,8 @@ int _alpm_str_cmp(const void *s1, const void *s2)
return(strcmp(s1, s2));
}
-/** Find a package file in an alpm cachedir.
- * @param filename name of package file to find
+/** Find a filename in a registered alpm cachedir.
+ * @param filename name of file to find
* @return malloced path of file, NULL if not found
*/
char *_alpm_filecache_find(const char* filename)
@@ -640,13 +660,7 @@ char SYMEXPORT *alpm_get_md5sum(const char *filename)
ret = md5_file(filename, output);
if (ret > 0) {
- if (ret == 1) {
- _alpm_log(PM_LOG_ERROR, _("md5: %s can't be opened\n"), filename);
- } else if (ret == 2) {
- _alpm_log(PM_LOG_ERROR, _("md5: %s can't be read\n"), filename);
- }
-
- return(NULL);
+ RET_ERR(PM_ERR_NOT_A_FILE, NULL);
}
/* Convert the result to something readable */
@@ -660,4 +674,52 @@ char SYMEXPORT *alpm_get_md5sum(const char *filename)
return(md5sum);
}
+int _alpm_test_md5sum(const char *filepath, const char *md5sum)
+{
+ char *md5sum2;
+ int ret;
+
+ md5sum2 = alpm_get_md5sum(filepath);
+
+ if(md5sum == NULL || md5sum2 == NULL) {
+ ret = -1;
+ } else if(strcmp(md5sum, md5sum2) != 0) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ FREE(md5sum2);
+ return(ret);
+}
+
+char *_alpm_archive_fgets(char *line, size_t size, struct archive *a)
+{
+ /* for now, just read one char at a time until we get to a
+ * '\n' char. we can optimize this later with an internal
+ * buffer. */
+ /* leave room for zero terminator */
+ char *last = line + size - 1;
+ char *i;
+
+ for(i = line; i < last; i++) {
+ int ret = archive_read_data(a, i, 1);
+ /* special check for first read- if null, return null,
+ * this indicates EOF */
+ if(i == line && (ret <= 0 || *i == '\0')) {
+ return(NULL);
+ }
+ /* check if read value was null or newline */
+ if(ret <= 0 || *i == '\0' || *i == '\n') {
+ last = i + 1;
+ break;
+ }
+ }
+
+ /* always null terminate the buffer */
+ *last = '\0';
+
+ return(line);
+}
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h
index e9e0af1f..6c7a05e9 100644
--- a/lib/libalpm/util.h
+++ b/lib/libalpm/util.h
@@ -30,6 +30,7 @@
#include <stdarg.h>
#include <time.h>
#include <sys/stat.h> /* struct stat */
+#include <archive.h> /* struct archive */
#ifdef ENABLE_NLS
#include <libintl.h> /* here so it doesn't need to be included elsewhere */
@@ -43,12 +44,17 @@
#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 STRDUP(r, s, action) do { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(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 FREE(p) do { if(p) { free(p); p = NULL; } } while(0)
+#define FREE(p) do { free(p); p = NULL; } while(0)
#define ASSERT(cond, action) do { if(!(cond)) { action; } } while(0)
+#define RET_ERR(err, ret) do { pm_errno = (err); \
+ _alpm_log(PM_LOG_DEBUG, "returning error %d from %s : %s\n", err, __func__, alpm_strerrorlast()); \
+ return(ret); } while(0)
+
int _alpm_makepath(const char *path);
int _alpm_makepath_mode(const char *path, mode_t mode);
int _alpm_copyfile(const char *src, const char *dest);
@@ -64,6 +70,8 @@ int _alpm_str_cmp(const void *s1, const void *s2);
char *_alpm_filecache_find(const char *filename);
const char *_alpm_filecache_setup(void);
int _alpm_lstat(const char *path, struct stat *buf);
+int _alpm_test_md5sum(const char *filepath, const char *md5sum);
+char *_alpm_archive_fgets(char *line, size_t size, struct archive *a);
#ifndef HAVE_STRVERSCMP
int strverscmp(const char *, const char *);