index : pacman | |
Archlinux32 fork of pacman | gitolite user |
summaryrefslogtreecommitdiff |
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 14d42a0c..7b737363 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -31,14 +31,15 @@ libalpm_la_SOURCES = \ 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..f759e7de 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_versioncmp(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); @@ -138,12 +121,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 +151,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 +159,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 +177,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 +195,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); @@ -437,7 +425,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)); } } } @@ -446,16 +434,14 @@ static int extract_single_file(struct archive *archive, } 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", @@ -465,14 +451,12 @@ static int extract_single_file(struct archive *archive, entryname, archive_error_string(archive)); alpm_logaction("error: could not extract %s (%s)\n", entryname, archive_error_string(archive)); - unlink(tempfile); - FREE(tempfile); FREE(hash_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) */ @@ -485,11 +469,8 @@ static int extract_single_file(struct archive *archive, } 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'; @@ -511,19 +492,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); } @@ -538,36 +520,45 @@ static int extract_single_file(struct archive *archive, _alpm_log(PM_LOG_DEBUG, "action: installing new file: %s\n", entryname); - 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"); 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 +566,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,7 +589,7 @@ 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", @@ -617,7 +608,7 @@ 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) { continue; @@ -625,10 +616,7 @@ static int extract_single_file(struct archive *archive, _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'; @@ -644,14 +632,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 +653,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 +675,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 +691,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); @@ -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..c6d11a5f 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 @@ -225,38 +222,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 +258,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 +273,105 @@ 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, + /** Package was extracted. */ 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 +404,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 +428,16 @@ 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); 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 +492,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 +507,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 +523,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..ae54e190 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; @@ -464,18 +444,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 +474,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 +507,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); + } } /** diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index ae373910..b3846ba0 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); diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c index 4cd0985e..7cc01c26 100644 --- a/lib/libalpm/be_files.c +++ b/lib/libalpm/be_files.c @@ -39,7 +39,6 @@ #include "log.h" #include "util.h" #include "alpm.h" -#include "error.h" #include "handle.h" #include "package.h" #include "delta.h" @@ -106,7 +105,7 @@ void _alpm_db_rewind(pmdb_t *db) 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 +114,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,14 +129,16 @@ 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); @@ -148,7 +149,6 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) 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; @@ -168,7 +168,9 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) /* 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, "..")) { + char *name; + + if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; } /* stat the entry, make sure it's a directory */ @@ -176,7 +178,9 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) if(stat(path, &sbuf) || !S_ISDIR(sbuf.st_mode)) { continue; } - strncpy(name, ent->d_name, PKG_FULLNAME_LEN); + + STRDUP(name, ent->d_name, return(NULL)); + /* truncate the string at the second-to-last hyphen, */ /* which will give us the package name */ if((ptr = rindex(name, '-'))) { @@ -185,10 +189,12 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) if((ptr = rindex(name, '-'))) { *ptr = '\0'; } - if(!strcmp(name, target)) { + if(strcmp(name, target) == 0) { found = 1; } + FREE(name); } + if(!found) { return(NULL); } @@ -199,7 +205,7 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) if(ent == NULL) { return(NULL); } - if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { + if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { isdir = 0; continue; } @@ -217,7 +223,7 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) return(NULL); } /* split the db entry name */ - if(_alpm_db_splitname(ent->d_name, pkg->name, pkg->version) != 0) { + if(splitname(ent->d_name, pkg) != 0) { _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"), ent->d_name); alpm_pkg_free(pkg); @@ -251,7 +257,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 +302,115 @@ 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, "%FILENAME%") == 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) { + STRDUP(info->filename, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%DESC%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(info->desc); - } else if(!strcmp(line, "%GROUPS%")) { + 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 +427,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 +455,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 +486,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 +560,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); } @@ -573,7 +572,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) fprintf(fp, "\n"); } if(local) { - if(info->url[0]) { + if(info->url) { fprintf(fp, "%%URL%%\n" "%s\n\n", info->url); } @@ -584,7 +583,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 +595,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,18 +694,16 @@ 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"); + 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) { + /* note the extra newline character, which is necessary! */ + fprintf(fp, "%%FORCE%%\n\n"); } fclose(fp); fp = NULL; diff --git a/lib/libalpm/cache.c b/lib/libalpm/cache.c index 0ad923a5..bfc4fd9e 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" @@ -81,10 +80,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 +111,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); @@ -208,33 +198,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 +238,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..68665e78 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) { 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..e8ae11a3 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -39,8 +39,7 @@ #include "alpm_list.h" #include "log.h" #include "util.h" -#include "error.h" -#include "server.h" +#include "dload.h" #include "handle.h" #include "cache.h" #include "alpm.h" @@ -190,14 +189,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); @@ -217,7 +211,6 @@ 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; @@ -250,29 +243,21 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db) /* 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); + 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) { - /* 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); + /* pm_errno was set by the download code */ + _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast()); + return(-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); - } + /* form the path to the db location */ snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename); /* remove the old dir */ @@ -293,6 +278,12 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db) if(_alpm_db_install(db, path) == -1) { return -1; } + /* 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); + _alpm_db_setlastupdate(db, newmtime); + } } return(0); @@ -319,8 +310,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 +318,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); } @@ -445,26 +434,21 @@ 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; @@ -500,18 +484,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(®, 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(®, name, 0, 0, 0) == 0 || strstr(name, targ))) { + matched = name; } /* check desc */ - else if (regexec(®, alpm_pkg_get_desc(pkg), 0, 0, 0) == 0) { - matched = alpm_pkg_get_desc(pkg); + else if (desc && regexec(®, desc, 0, 0, 0) == 0) { + matched = desc; } /* check provides */ /* TODO: should we be doing this, and should we print something diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 8c8c9bd7..743fa788 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; 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..b171ccc7 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); + FREE(dep->name); + FREE(dep->version); + FREE(dep); } -static void _alpm_graph_free(void *data) -{ - pmgraph_t *graph = data; - alpm_list_free(graph->children); - free(graph); -} - -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); @@ -217,6 +203,31 @@ static int satisfycmp(const void *pkg, const void *depend) /** 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_list_find(_alpm_db_get_pkgcache(db), dep, satisfycmp)) { + ret = alpm_list_add(ret, target); + } + _alpm_dep_free(dep); + } + return(ret); +} + +/** 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 reversedeps handles the backward dependencies * @param remove an alpm_list_t* of packages to be removed * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade) @@ -264,8 +275,7 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps, _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 +288,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_find(modified, depend, satisfycmp); /* 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) && + if(causingpkg && !alpm_list_find(upgrade, depend, satisfycmp) && !alpm_list_find(dblist, depend, satisfycmp)) { 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); } } @@ -356,7 +366,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 +375,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 +401,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,7 +438,7 @@ 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)) { return(0); @@ -439,15 +460,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(lpkg->name, targets)) { + return(0); + } + break; + } } } - FREELIST(requiredby); /* it's ok to remove */ return(1); @@ -523,7 +546,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,7 +571,8 @@ 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(alpm_pkg_get_name(sync), remove) + && !_alpm_pkg_find(alpm_pkg_get_name(sync), *list); if(!found) { continue; } @@ -570,7 +594,8 @@ 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(alpm_pkg_get_name(sync), remove) + && !_alpm_pkg_find(alpm_pkg_get_name(sync), *list); if(!found) { continue; } @@ -611,7 +636,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 +653,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 +673,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 +683,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 +693,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 +703,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 +713,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 +721,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 +751,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..fe851288 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -29,31 +29,28 @@ /* 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); #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..1cc379c6 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,7 +50,9 @@ 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); } @@ -74,7 +76,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..5f8fdec4 100644 --- a/lib/libalpm/group.h +++ b/lib/libalpm/group.h @@ -19,17 +19,16 @@ #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); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 36822285..247ef71d 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -36,10 +36,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; 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/package.c b/lib/libalpm/package.c index 287c2ce4..ffaa96b3 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -42,7 +42,6 @@ #include "alpm_list.h" #include "log.h" #include "util.h" -#include "error.h" #include "db.h" #include "cache.h" #include "delta.h" @@ -105,8 +104,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; @@ -116,28 +114,16 @@ 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); } @@ -166,17 +152,6 @@ 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; } @@ -520,7 +495,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); @@ -756,15 +731,12 @@ 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(name) { + STRDUP(pkg->name, name, RET_ERR(PM_ERR_MEMORY, pkg)); } - if(version && version[0] != 0) { - strncpy(pkg->version, version, PKG_VERSION_LEN); - } else { - pkg->version[0] = '\0'; + + if(version) { + STRDUP(pkg->version, version, RET_ERR(PM_ERR_MEMORY, pkg)); } return(pkg); @@ -772,31 +744,51 @@ pmpkg_t *_alpm_pkg_new(const char *name, const char *version) 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); } @@ -809,16 +801,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); } @@ -866,15 +870,18 @@ int _alpm_pkg_cmp(const void *p1, const void *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 +int _alpm_pkgname_pkg_cmp(const void *pkgname, const void *package) +{ + return(strcmp(alpm_pkg_get_name((pmpkg_t *) package), (char *) pkgname)); +} + + +/* Parses the package description file for the current package. This + * is handed the struct archive when the .PKGINFO file is open. * Returns: 0 on success, 1 on error - * */ -static int parse_descfile(const char *descfile, pmpkg_t *info) +static int parse_descfile(struct archive *a, pmpkg_t *info) { - FILE* fp = NULL; char line[PATH_MAX]; char *ptr = NULL; char *key = NULL; @@ -882,13 +889,8 @@ static int parse_descfile(const char *descfile, pmpkg_t *info) 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); + /* 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] == '#') { @@ -898,26 +900,26 @@ static int parse_descfile(const char *descfile, pmpkg_t *info) 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); + info->name ? info->name : "error", linenum); } else { - _alpm_strtrim(key); - _alpm_strtrim(ptr); + key = _alpm_strtrim(key); + ptr = _alpm_strtrim(ptr); if(!strcmp(key, "pkgname")) { - strncpy(info->name, ptr, sizeof(info->name)); + STRDUP(info->name, ptr, RET_ERR(PM_ERR_MEMORY, -1)); } else if(!strcmp(key, "pkgver")) { - strncpy(info->version, ptr, sizeof(info->version)); + STRDUP(info->version, ptr, RET_ERR(PM_ERR_MEMORY, -1)); } else if(!strcmp(key, "pkgdesc")) { - strncpy(info->desc, ptr, sizeof(info->desc)); + STRDUP(info->desc, ptr, RET_ERR(PM_ERR_MEMORY, -1)); } 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)); + STRDUP(info->url, ptr, RET_ERR(PM_ERR_MEMORY, -1)); } 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 + 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); info->builddate = mktime(&tmp_tm); @@ -926,14 +928,14 @@ static int parse_descfile(const char *descfile, pmpkg_t *info) info->builddate = atol(ptr); } } else if(!strcmp(key, "packager")) { - strncpy(info->packager, ptr, sizeof(info->packager)); + STRDUP(info->packager, ptr, RET_ERR(PM_ERR_MEMORY, -1)); } else if(!strcmp(key, "arch")) { - strncpy(info->arch, ptr, sizeof(info->arch)); + STRDUP(info->arch, ptr, RET_ERR(PM_ERR_MEMORY, -1)); } 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); + 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)); @@ -947,13 +949,11 @@ static int parse_descfile(const char *descfile, pmpkg_t *info) 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); + info->name ? info->name : "error", linenum); } } line[0] = '\0'; } - fclose(fp); - unlink(descfile); return(0); } @@ -973,8 +973,6 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) struct archive *archive; struct archive_entry *entry; pmpkg_t *info = NULL; - char *descfile = NULL; - int fd = -1; struct stat st; ALPM_LOG_FUNC; @@ -984,7 +982,7 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) } 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); @@ -1005,48 +1003,28 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) 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) { + if(parse_descfile(archive, info) != 0) { _alpm_log(PM_LOG_ERROR, _("could not parse package description file in %s\n"), pkgfile); goto pkg_invalid; } - if(!strlen(info->name)) { + if(info->name == NULL || strlen(info->name) == 0) { _alpm_log(PM_LOG_ERROR, _("missing package name in %s\n"), pkgfile); goto pkg_invalid; } - if(!strlen(info->version)) { + if(info->version == NULL || strlen(info->version) == 0) { _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; @@ -1061,7 +1039,7 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) 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; + pm_errno = PM_ERR_LIBARCHIVE; goto error; } @@ -1074,7 +1052,7 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) 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; + pm_errno = PM_ERR_LIBARCHIVE; goto error; } @@ -1090,13 +1068,13 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) info->origin_data.file = strdup(pkgfile); if(full) { - /* "checking for conflicts" requires a sorted list, so we ensure that here */ + /* "checking for conflicts" requires a sorted list, 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 */ + /* get rid of any partial filelist we may have collected, it is invalid */ FREELIST(info->files); info->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS; } @@ -1105,13 +1083,6 @@ pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) 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); diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index d6c3eff9..0ba8aac4 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,6 +70,8 @@ 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); @@ -90,6 +79,7 @@ pmpkg_t* _alpm_pkg_new(const char *name, const char *version); 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_pkgname_pkg_cmp(const void *pkgname, const void *package); 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); 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..f2e84ef5 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" @@ -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(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); + } + } + 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; + trans->packages = alpm_list_remove(trans->packages, miss->causingpkg, + _alpm_pkgname_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; @@ -102,31 +155,19 @@ int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) _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 +176,14 @@ 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) { _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..357b01f2 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(alpm_pkg_get_name(local), replaced)) { _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,41 +348,85 @@ 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; - p1 = alpm_sync_get_pkg(sp1); - p2 = alpm_sync_get_pkg(sp2); + p1 = alpm_sync_get_pkg(sp1); + p2 = alpm_sync_get_pkg(sp2); return(strcmp(alpm_pkg_get_name(p1), alpm_pkg_get_name(p2))); } +/** 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; + + 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) { alpm_list_t *deps = NULL; @@ -397,14 +443,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 +459,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 +474,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 +511,126 @@ 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 */ + if(alpm_list_find(alpm_pkg_get_provides(sync1->pkg), + conflict->package2, _alpm_prov_cmp)) { + rsync = sync2; + sync = sync1; + } else if(alpm_list_find(alpm_pkg_get_provides(sync2->pkg), + conflict->package1, _alpm_prov_cmp)) { + 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); + goto cleanup; + } + + /* 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(conflict->package2, sync->removes)) { + 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 +642,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 +664,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 +680,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 +770,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 +800,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 +815,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 +828,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 +880,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 +915,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 +941,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 +951,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(pkg->name, tr->packages)) { + if(_alpm_trans_addtarget(tr, pkg->name) == -1) { + goto error; } + replaces++; } } } @@ -1175,7 +983,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 +996,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 +1011,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 +1022,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 +1054,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 +1062,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..92e99914 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" @@ -216,27 +215,31 @@ int _alpm_makepath_mode(const char *path, mode_t mode) return(0); } +#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, 1, CPBUFSIZE, 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 +249,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 +376,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 +394,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 +420,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 +551,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 +656,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 +670,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 *); |