[pacman-dev] Round 2: Add delta information to libalpm.
Here are the updated patches for adding delta downloading to libalpm. I had originally thought that if a delta could not be downloaded (due to md5sum or file deleted on the server), the package file should be downloaded instead. I decided not to do this because some users may be annoyed at seeing a 7MB download size but end up downloading 100MB openoffice package. If the md5sum is not correct, the output is mangled a bit. I am not sure what causes this. Proceed with installation? [Y/n] y :: Retrieving packages from test... wbox-3-1_to_4-1-i686... 7.9K 17.1M/s 00:00:00 [#####################] 100% wbox-4-1_to_4-2-i686... 0.4K 1087.1K/s 00:00:00 [#####################] 100% :: File wbox-4-1_to_4-2-i686.delta is corrupted. Do you want to delete it? [Y/n] checking delta integrity... error: failed to commit transaction (corrupted delta) Errors occurred, no packages were upgraded. Also, is it just me, or do 78% of the pactests fail?
Signed-off-by: Nathan Jones <nathanj@insightbb.com> --- scripts/repo-add.sh.in | 58 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 57 insertions(+), 1 deletions(-) diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index cb741d7..786bf1c 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -97,6 +97,37 @@ write_list_entry() { fi } +# write a delta entry to the pacman database +# arg1 - path to delta +db_write_delta() +{ + # blank out all variables and set deltafile + local deltafile=$(readlink -f "$1") + local filename=$(basename "$deltafile") + local deltavars pkgname fromver tover arch csize md5sum + + # format of the delta filename: + # (package)-(fromver)_to_(tover)-(arch).delta + deltavars=( $(echo "$filename" | sed -e 's/\(.*\)-\(.*-.*\)_to_\(.*-.*\)-\(.*\).delta/\1 \2 \3 \4/') ) + pkgname=${deltavars[0]} + fromver=${deltavars[1]} + tover=${deltavars[2]} + arch=${deltavars[3]} + + # get md5sum and size of delta + md5sum="$(md5sum "$deltafile" | cut -d ' ' -f 1)" + csize=$(du -b -L "$deltafile" | cut -f 1) + + # ensure variables were found + if [ -z "$pkgname" -o -z "$fromver" -o -z "$tover" -o -z "$arch" ]; then + return 1 + fi + + # add the entry for this delta file + echo -e "$fromver $tover $csize $filename $md5sum" >>deltas +} # end db_write_delta + + # write an entry to the pacman database # arg1 - path to package db_write_entry() @@ -105,7 +136,8 @@ db_write_entry() local pkgfile=$(readlink -f "$1") local pkgname pkgver pkgdesc url builddate packager csize size \ group depend backup license replaces provides conflict \ - _groups _depends _backups _licenses _replaces _provides _conflicts + _groups _depends _backups _licenses _replaces _provides _conflicts \ + startdir local OLDIFS="$IFS" # IFS (field seperator) is only the newline character @@ -133,6 +165,7 @@ db_write_entry() # get compressed size of package csize=$(du -b -L "$pkgfile" | cut -f 1) + startdir=$(pwd) pushd "$gstmpdir" 2>&1 >/dev/null # ensure $pkgname and $pkgver variables were found @@ -183,8 +216,31 @@ db_write_entry() write_list_entry "CONFLICTS" "$_conflicts" "depends" write_list_entry "PROVIDES" "$_provides" "depends" + # create deltas entry if there are delta files + for delta in $startdir/$pkgname-*-*_to_*-*-$arch.delta; do + if [ -f "$delta" ]; then + # create deltas file if it does not already exist + if [ -f "deltas" ]; then + echo -n # nothing + else + msg2 "$(gettext "Creating 'deltas' db entry...")" + echo -e "%DELTAS%" >>deltas + fi + + # write this delta entry + if db_write_delta "$delta"; then + msg2 "$(gettext "Added delta '%s'")" "$(basename "$delta")" + else + msg2 "$(gettext "Could not add delta '%s'")" "$(basename "$delta")" + fi + fi + done + # add the final newline + [ -f "deltas" ] && echo -e "" >>deltas + # preserve the modification time touch -r "$pkgfile" desc depends + [ -f "deltas" ] && touch -r "$pkgfile" deltas popd 2>&1 >/dev/null } # end db_write_entry -- 1.5.3.4
Signed-off-by: Nathan Jones <nathanj@insightbb.com> --- lib/libalpm/Makefile.am | 1 + lib/libalpm/alpm.h | 12 ++ lib/libalpm/alpm_list.c | 18 +++ lib/libalpm/alpm_list.h | 1 + lib/libalpm/be_files.c | 19 +++ lib/libalpm/db.h | 3 +- lib/libalpm/delta.c | 265 ++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/delta.h | 45 ++++++++ lib/libalpm/package.c | 15 +++ lib/libalpm/package.h | 1 + lib/libalpm/po/POTFILES.in | 1 + 11 files changed, 380 insertions(+), 1 deletions(-) create mode 100644 lib/libalpm/delta.c create mode 100644 lib/libalpm/delta.h diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 6948239..49ce14c 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -18,6 +18,7 @@ libalpm_la_SOURCES = \ cache.h cache.c \ conflict.h conflict.c \ db.h db.c \ + delta.h delta.c \ deps.h deps.c \ error.h error.c \ group.h group.c \ diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 6eda210..5f37d82 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -45,6 +45,7 @@ extern "C" { 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; @@ -207,12 +208,23 @@ alpm_list_t *alpm_pkg_get_optdepends(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_requiredby(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_conflicts(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_provides(pmpkg_t *pkg); +alpm_list_t *alpm_pkg_get_deltas(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_replaces(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_files(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_backup(pmpkg_t *pkg); unsigned short alpm_pkg_has_scriptlet(pmpkg_t *pkg); /* + * Deltas + */ + +char *alpm_delta_get_from(pmdelta_t *delta); +char *alpm_delta_get_to(pmdelta_t *delta); +unsigned long alpm_delta_get_size(pmdelta_t *delta); +char *alpm_delta_get_filename(pmdelta_t *delta); +char *alpm_delta_get_md5sum(pmdelta_t *delta); + +/* * Groups */ const char *alpm_grp_get_name(const pmgrp_t *grp); diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index 5671b4a..2301411 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -379,6 +379,24 @@ alpm_list_t SYMEXPORT *alpm_list_strdup(const alpm_list_t *list) } /** + * @brief Copy a list, without copying data. + * + * @param list the list to copy + * + * @return a copy of the original list + */ +alpm_list_t SYMEXPORT *alpm_list_copy(const alpm_list_t *list) +{ + const alpm_list_t *lp = list; + alpm_list_t *newlist = NULL; + while(lp) { + newlist = alpm_list_add(newlist, lp->data); + lp = lp->next; + } + return(newlist); +} + +/** * @brief Create a new list in reverse order. * * @param list the list to copy diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index a2a06f4..8fce280 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -60,6 +60,7 @@ alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_li alpm_list_t *alpm_list_remove_node(alpm_list_t *node); alpm_list_t *alpm_list_remove_dupes(const alpm_list_t *list); alpm_list_t *alpm_list_strdup(const alpm_list_t *list); +alpm_list_t *alpm_list_copy(const alpm_list_t *list); alpm_list_t *alpm_list_reverse(alpm_list_t *list); /* item accessors */ diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c index 2bfdb95..59155cf 100644 --- a/lib/libalpm/be_files.c +++ b/lib/libalpm/be_files.c @@ -44,6 +44,7 @@ #include "error.h" #include "handle.h" #include "package.h" +#include "delta.h" /* This function is used to convert the downloaded db file to the proper backend @@ -484,6 +485,24 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) fp = NULL; } + /* DELTAS */ + if(inforeq & INFRQ_DELTAS) { + 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%")) { + while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { + info->deltas = alpm_list_add(info->deltas, _alpm_delta_parse(line)); + } + } + } + fclose(fp); + fp = NULL; + } + } + /* INSTALL */ if(inforeq & INFRQ_SCRIPTLET) { snprintf(path, PATH_MAX, "%s/%s-%s/install", db->path, info->name, info->version); diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 3ee4977..16e1298 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -33,8 +33,9 @@ typedef enum _pmdbinfrq_t { INFRQ_DEPENDS = 0x04, INFRQ_FILES = 0x08, INFRQ_SCRIPTLET = 0x10, + INFRQ_DELTAS = 0x20, /* ALL should be sum of all above */ - INFRQ_ALL = 0x1F + INFRQ_ALL = 0x3F } pmdbinfrq_t; /* Database */ diff --git a/lib/libalpm/delta.c b/lib/libalpm/delta.c new file mode 100644 index 0000000..00ed46c --- /dev/null +++ b/lib/libalpm/delta.c @@ -0,0 +1,265 @@ +/* + * delta.c + * + * Copyright (c) 2007 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> + +/* libalpm */ +#include "delta.h" +#include "util.h" +#include "log.h" +#include "alpm_list.h" +#include "alpm.h" + +/** \addtogroup alpm_deltas Delta Functions + * @brief Functions to manipulate libalpm deltas + * @{ + */ + +char SYMEXPORT *alpm_delta_get_from(pmdelta_t *delta) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(delta != NULL, return(NULL)); + + return(delta->from); +} + +char SYMEXPORT *alpm_delta_get_to(pmdelta_t *delta) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(delta != NULL, return(NULL)); + + return(delta->to); +} + +unsigned long SYMEXPORT alpm_delta_get_size(pmdelta_t *delta) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(delta != NULL, return(-1)); + + return(delta->size); +} + +char SYMEXPORT *alpm_delta_get_filename(pmdelta_t *delta) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(delta != NULL, return(NULL)); + + return(delta->filename); +} + +char SYMEXPORT *alpm_delta_get_md5sum(pmdelta_t *delta) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(delta != NULL, return(NULL)); + + return(delta->md5sum); +} + +/** @} */ + +/** 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) +{ + unsigned long sum = 0; + alpm_list_t *dlts = deltas; + + while(dlts) { + pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts); + sum += d->size; + + dlts = alpm_list_next(dlts); + } + + return(sum); +} + +/** 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); + + if(!fname) { + sum += d->size; + } + + FREE(fname); + + dlts = alpm_list_next(dlts); + } + + return(sum); +} + +/** 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); + + /* If this vertex has already been visited in the path, go to the + * next vertex. */ + if(alpm_list_find(path, v)) + continue; + + /* 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); + alpm_list_free(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); + } + } + } + } + + return(shortest); +} + +/** 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. + */ +alpm_list_t *_alpm_shortest_delta_path(alpm_list_t *deltas, const char *from, + const char *to) +{ + alpm_list_t *path = NULL; + + path = shortest_delta_path(deltas, from, to, path); + + return(path); +} + +/** Parses the string representation of a pmdelta_t object. + * + * This function assumes that the string is in the correct format. + * + * @param line the string to parse + * + * @return A pointer to the new pmdelta_t object + */ +pmdelta_t *_alpm_delta_parse(char *line) +{ + pmdelta_t *delta; + char *tmp = line, *tmp2; + + delta = malloc(sizeof(pmdelta_t)); + + tmp2 = tmp; + tmp = strchr(tmp, ' '); + *(tmp++) = '\0'; + strncpy(delta->from, tmp2, DLT_VERSION_LEN); + + tmp2 = tmp; + tmp = strchr(tmp, ' '); + *(tmp++) = '\0'; + strncpy(delta->to, tmp2, DLT_VERSION_LEN); + + tmp2 = tmp; + tmp = strchr(tmp, ' '); + *(tmp++) = '\0'; + delta->size = atol(tmp2); + + tmp2 = tmp; + tmp = strchr(tmp, ' '); + *(tmp++) = '\0'; + strncpy(delta->filename, tmp2, DLT_FILENAME_LEN); + + strncpy(delta->md5sum, tmp, DLT_MD5SUM_LEN); + + return(delta); +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h new file mode 100644 index 0000000..67dbeb4 --- /dev/null +++ b/lib/libalpm/delta.h @@ -0,0 +1,45 @@ +/* + * delta.h + * + * Copyright (c) 2007 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef _ALPM_DELTA_H +#define _ALPM_DELTA_H + +#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]; +}; + +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); + +#endif /* _ALPM_DELTA_H */ + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 38e6e4c..6a8e0d8 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -446,6 +446,20 @@ alpm_list_t SYMEXPORT *alpm_pkg_get_provides(pmpkg_t *pkg) return pkg->provides; } +alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(handle != NULL, return(NULL)); + ASSERT(pkg != NULL, return(NULL)); + + if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DELTAS)) { + _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS); + } + return pkg->deltas; +} + alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg) { ALPM_LOG_FUNC; @@ -725,6 +739,7 @@ void _alpm_pkg_free(pmpkg_t *pkg) FREELIST(pkg->groups); FREELIST(pkg->provides); FREELIST(pkg->replaces); + FREELIST(pkg->deltas); if(pkg->origin == PKG_FROM_FILE) { FREE(pkg->origin_data.file); } diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index 42ebe0e..daaeb36 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -75,6 +75,7 @@ struct __pmpkg_t { alpm_list_t *requiredby; alpm_list_t *conflicts; alpm_list_t *provides; + alpm_list_t *deltas; /* internal */ pmpkgfrom_t origin; /* Replaced 'void *data' with this union as follows: diff --git a/lib/libalpm/po/POTFILES.in b/lib/libalpm/po/POTFILES.in index caf68c3..97df339 100644 --- a/lib/libalpm/po/POTFILES.in +++ b/lib/libalpm/po/POTFILES.in @@ -9,6 +9,7 @@ lib/libalpm/cache.c lib/libalpm/conflict.c lib/libalpm/db.c lib/libalpm/deps.c +lib/libalpm/delta.c lib/libalpm/error.c lib/libalpm/group.c lib/libalpm/handle.c -- 1.5.3.4
This will allow deltas and packages to share the md5sum checking code. Signed-off-by: Nathan Jones <nathanj@insightbb.com> --- lib/libalpm/sync.c | 133 +++++++++++++++++++++++++++++++++++----------------- 1 files changed, 89 insertions(+), 44 deletions(-) diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index d24a1e5..abc90de 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -700,6 +700,90 @@ cleanup: return(ret); } +/** Compares the md5sum of a file to the expected value. + * + * If the md5sum does not match, the user is asked whether the file + * should be deleted. + * + * @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 + */ +static int test_md5sum(pmtrans_t *trans, const char *filename, + const char *md5sum, alpm_list_t **data) +{ + char *filepath; + char *md5sum2; + char *errormsg = NULL; + int ret = 0; + + filepath = _alpm_filecache_find(filename); + md5sum2 = alpm_get_md5sum(filepath); + + if(md5sum == NULL) { + /* 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((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) { + int doremove = 0; + if((errormsg = calloc(512, sizeof(char))) == NULL) { + RET_ERR(PM_ERR_MEMORY, -1); + } + QUESTION(trans, PM_TRANS_CONV_CORRUPTED_PKG, (char *)filename, + NULL, NULL, &doremove); + if(doremove) { + unlink(filepath); + } + 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 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); +} + int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) { alpm_list_t *i, *j, *files = NULL; @@ -761,54 +845,15 @@ 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; pmpkg_t *spkg = sync->pkg; - const char *filename; - char *filepath; - char *md5sum1, *md5sum2; - char *ptr=NULL; + int ret = 0; - filename = alpm_pkg_get_filename(spkg); - md5sum1 = spkg->md5sum; + ret = test_pkg_md5sum(trans, spkg, data); - if(md5sum1 == NULL) { - /* TODO wtf is this? malloc'd strings for error messages? */ - if((ptr = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(ptr, 512, _("can't get md5 checksum for package %s\n"), filename); - *data = alpm_list_add(*data, ptr); - retval = 1; - continue; - } - - filepath = _alpm_filecache_find(filename); - - md5sum2 = alpm_get_md5sum(filepath); - if(md5sum2 == NULL) { - if((ptr = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(ptr, 512, _("can't get md5 checksum for package %s\n"), filename); - *data = alpm_list_add(*data, ptr); - retval = 1; - continue; - } - if(strcmp(md5sum1, md5sum2) != 0) { - int doremove=0; - if((ptr = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - QUESTION(trans, PM_TRANS_CONV_CORRUPTED_PKG, (char *)filename, - NULL, NULL, &doremove); - if(doremove) { - unlink(filepath); - } - snprintf(ptr, 512, _("archive %s was corrupted (bad MD5 checksum)\n"), - filename); - *data = alpm_list_add(*data, ptr); + if(ret == 1) { retval = 1; + } else if(ret == -1) { /* -1 is for serious errors */ + RET_ERR(pm_errno, -1); } - FREE(filepath); - FREE(md5sum2); } if(retval) { pm_errno = PM_ERR_PKG_CORRUPTED; -- 1.5.3.4
Delta files will be used if the size is smaller than a percent (MAX_DELTA_RATIO) of the package size. Signed-off-by: Nathan Jones <nathanj@insightbb.com> --- doc/pacman.conf.5.txt | 4 + lib/libalpm/alpm.h | 11 ++ lib/libalpm/error.c | 5 + lib/libalpm/handle.c | 6 + lib/libalpm/handle.h | 1 + lib/libalpm/sync.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++- lib/libalpm/util.h | 3 + src/pacman/callback.c | 23 +++++- src/pacman/pacman.c | 3 + 9 files changed, 300 insertions(+), 4 deletions(-) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index d422a4b..06ba81d 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -105,6 +105,10 @@ Options *ShowSize*:: Display the size of individual packages for '\--sync' and '\--query' modes. +*UseDelta*:: + Download delta files instead of complete packages if possible. Requires + the xdelta program to be installed. + Repository Sections ------------------- diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 5f37d82..a4eaafa 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -138,6 +138,7 @@ void alpm_option_set_xfercommand(const char *cmd); unsigned short alpm_option_get_nopassiveftp(); void alpm_option_set_nopassiveftp(unsigned short nopasv); +void alpm_option_set_usedelta(unsigned short usedelta); pmdb_t *alpm_option_get_localdb(); alpm_list_t *alpm_option_get_syncdbs(); @@ -294,6 +295,13 @@ typedef enum _pmtransevt_t { PM_TRANS_EVT_EXTRACT_DONE, PM_TRANS_EVT_INTEGRITY_START, PM_TRANS_EVT_INTEGRITY_DONE, + PM_TRANS_EVT_DELTA_INTEGRITY_START, + PM_TRANS_EVT_DELTA_INTEGRITY_DONE, + PM_TRANS_EVT_DELTA_PATCHES_START, + PM_TRANS_EVT_DELTA_PATCHES_DONE, + PM_TRANS_EVT_DELTA_PATCH_START, + PM_TRANS_EVT_DELTA_PATCH_DONE, + PM_TRANS_EVT_DELTA_PATCH_FAILED, PM_TRANS_EVT_PRINTURI, PM_TRANS_EVT_RETRIEVE_START, } pmtransevt_t; @@ -442,6 +450,9 @@ enum _pmerrno_t { PM_ERR_PKG_INVALID_NAME, PM_ERR_PKG_CORRUPTED, PM_ERR_PKG_REPO_NOT_FOUND, + /* Deltas */ + PM_ERR_DLT_CORRUPTED, + PM_ERR_DLT_PATCHFAILED, /* Groups */ PM_ERR_GRP_NOT_FOUND, /* Dependencies */ diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index f81d22d..44d1c60 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -123,6 +123,11 @@ const char SYMEXPORT *alpm_strerror(int err) return _("corrupted package"); case PM_ERR_PKG_REPO_NOT_FOUND: return _("no such repository"); + /* Deltas */ + case PM_ERR_DLT_CORRUPTED: + return _("corrupted delta"); + case PM_ERR_DLT_PATCHFAILED: + return _("delta patch failed"); /* Groups */ case PM_ERR_GRP_NOT_FOUND: return _("group not found"); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index e8f2147..242bbe5 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -64,6 +64,7 @@ pmhandle_t *_alpm_handle_new() handle->cachedirs = NULL; handle->lockfile = NULL; handle->logfile = NULL; + handle->usedelta = 0; return(handle); } @@ -496,4 +497,9 @@ void SYMEXPORT alpm_option_set_nopassiveftp(unsigned short nopasv) handle->nopassiveftp = nopasv; } +void SYMEXPORT alpm_option_set_usedelta(unsigned short usedelta) +{ + handle->usedelta = usedelta; +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index cf2e9d5..d8edf00 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -61,6 +61,7 @@ typedef struct _pmhandle_t { unsigned short nopassiveftp; /* Don't use PASV ftp connections */ time_t upgradedelay; /* Time to wait before upgrading a package */ char *xfercommand; /* External download command */ + unsigned short usedelta; /* Download deltas if possible */ } pmhandle_t; extern pmhandle_t *handle; diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index abc90de..d5f6500 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -48,6 +48,7 @@ #include "handle.h" #include "alpm.h" #include "server.h" +#include "delta.h" pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data) { @@ -700,6 +701,148 @@ 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); +} + +/** Applies delta files to create an upgraded package file. + * + * All intermediate files are deleted, leaving only the starting and + * 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) +{ + /* 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; + 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]; + + pkg = alpm_list_getdata(p); + p = alpm_list_next(p); + + d = alpm_list_getdata(p); + p = alpm_list_next(p); + + /* if patching fails, ignore the rest of that package's deltas */ + if(lastpkg_failed) { + if(pkg == lastpkg) { + continue; + } else { + lastpkg_failed = 0; + } + } + + /* 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; + } + } else { + EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL); + lastpkg_failed = 1; + ret = 1; + } + } + + return(ret); +} + /** Compares the md5sum of a file to the expected value. * * If the md5sum does not match, the user is asked whether the file @@ -762,6 +905,29 @@ static int test_md5sum(pmtrans_t *trans, const char *filename, 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; + 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 @@ -787,6 +953,7 @@ 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; pmtrans_t *tr = NULL; int replaces = 0, retval = 0; const char *cachedir = NULL; @@ -817,8 +984,42 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) } else { char *fpath = _alpm_filecache_find(fname); if(!fpath) { - /* file is not in the cache dir, so add it to the list */ - files = alpm_list_add(files, strdup(fname)); + 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); + } + + 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)); + } + } else { + /* not using deltas, so add the file to the download list */ + files = alpm_list_add(files, strdup(fname)); + } } FREE(fpath); } @@ -839,7 +1040,48 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) return(0); } - /* Check integrity of files */ + if(handle->usedelta) { + int ret = 0; + + /* only output if there are deltas to work with */ + if(deltas) { + /* 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); + + 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(retval) { + pm_errno = PM_ERR_DLT_CORRUPTED; + 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); + 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; + goto error; + } + } + + /* Check integrity of packages */ EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL); for(i = trans->packages; i; i = i->next) { diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 5ebc70c..17fa123 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -67,6 +67,9 @@ char *strsep(char **, const char *); #define SYMEXPORT __attribute__((visibility("default"))) #define SYMHIDDEN __attribute__((visibility("internal"))) +/* max percent of package size to download deltas */ +#define MAX_DELTA_RATIO 0.7 + #endif /* _ALPM_UTIL_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 6d25713..aec9753 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -236,6 +236,27 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) case PM_TRANS_EVT_INTEGRITY_DONE: printf(_("done.\n")); break; + case PM_TRANS_EVT_DELTA_INTEGRITY_START: + printf(_("checking delta integrity... ")); + break; + case PM_TRANS_EVT_DELTA_INTEGRITY_DONE: + printf(_("done.\n")); + break; + case PM_TRANS_EVT_DELTA_PATCHES_START: + printf(_("applying deltas...\n")); + break; + case PM_TRANS_EVT_DELTA_PATCHES_DONE: + /* nothing */ + break; + case PM_TRANS_EVT_DELTA_PATCH_START: + printf(_("generating %s with %s... "), (char *)data1, (char *)data2); + break; + case PM_TRANS_EVT_DELTA_PATCH_DONE: + printf(_("done.\n")); + break; + case PM_TRANS_EVT_DELTA_PATCH_FAILED: + printf(_("failed.\n")); + break; case PM_TRANS_EVT_PRINTURI: printf("%s/%s\n", (char*)data1, (char*)data2); break; @@ -309,7 +330,7 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, break; case PM_TRANS_CONV_CORRUPTED_PKG: if(!config->noconfirm) { - snprintf(str, LOG_STR_LEN, _(":: Archive %s is corrupted. Do you want to delete it? [Y/n] "), + snprintf(str, LOG_STR_LEN, _(":: File %s is corrupted. Do you want to delete it? [Y/n] "), (char *)data1); *response = yesno(str); } else { diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 8474020..2f6f928 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -548,6 +548,9 @@ static int _parseconfig(const char *file, const char *givensection, } else if(strcmp(key, "ShowSize") == 0 || strcmp(upperkey, "SHOWSIZE") == 0) { config->showsize = 1; pm_printf(PM_LOG_DEBUG, "config: showsize\n"); + } else if(strcmp(key, "UseDelta") == 0 || strcmp(upperkey, "USEDELTA") == 0) { + alpm_option_set_usedelta(1); + pm_printf(PM_LOG_DEBUG, "config: usedelta\n"); } else { pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' not recognized.\n"), file, linenum, key); -- 1.5.3.4
This displays the download size, taking into account delta files and cached files. This closes FS#4182. Signed-off-by: Nathan Jones <nathanj@insightbb.com> --- lib/libalpm/alpm.h | 2 ++ lib/libalpm/sync.c | 34 ++++++++++++++++++++++++++++++++++ src/pacman/query.c | 2 +- src/pacman/sync.c | 2 +- src/pacman/util.c | 24 ++++++++---------------- src/pacman/util.h | 2 +- 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index a4eaafa..880bbeb 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -215,6 +215,8 @@ alpm_list_t *alpm_pkg_get_files(pmpkg_t *pkg); alpm_list_t *alpm_pkg_get_backup(pmpkg_t *pkg); unsigned short alpm_pkg_has_scriptlet(pmpkg_t *pkg); +unsigned long alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local); + /* * Deltas */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index d5f6500..3e12ffb 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -749,6 +749,40 @@ static alpm_list_t *pkg_upgrade_delta_path(pmpkg_t *newpkg, pmdb_t *db_local) 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) +{ + 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); +} + /** Applies delta files to create an upgraded package file. * * All intermediate files are deleted, leaving only the starting and diff --git a/src/pacman/query.c b/src/pacman/query.c index 4e4002c..8a01d82 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -219,7 +219,7 @@ static int query_upgrades(void) printf(_("Checking for package upgrades... \n")); if((syncpkgs = alpm_db_get_upgrades()) != NULL) { - display_targets(syncpkgs); + display_targets(syncpkgs, db_local); return(0); } diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 6a7d50e..bf6eed1 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -601,7 +601,7 @@ int sync_trans(alpm_list_t *targets, int sync_only) if(!(alpm_trans_get_flags() & PM_TRANS_FLAG_PRINTURIS)) { int confirm; - display_targets(packages); + display_targets(packages, db_local); printf("\n"); if(config->op_s_downloadonly) { diff --git a/src/pacman/util.c b/src/pacman/util.c index 2c00753..4d6712a 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -329,14 +329,15 @@ void list_display(const char *title, const alpm_list_t *list) * retrieved from a transaction object */ /* TODO move to output.c? or just combine util and output */ -void display_targets(const alpm_list_t *syncpkgs) +void display_targets(const alpm_list_t *syncpkgs, pmdb_t *db_local) { char *str; const alpm_list_t *i, *j; alpm_list_t *targets = NULL, *to_remove = NULL; /* TODO these are some messy variable names */ - unsigned long size = 0, isize = 0, rsize = 0, dispsize = 0; - double mbsize = 0.0, mbisize = 0.0, mbrsize = 0.0, mbdispsize = 0.0; + unsigned long size = 0, isize = 0, rsize = 0, dispsize = 0, dlsize = 0; + double mbsize = 0.0, mbisize = 0.0, mbrsize = 0.0, mbdispsize = 0.0, + mbdlsize = 0.0; for(i = syncpkgs; i; i = alpm_list_next(i)) { pmsyncpkg_t *sync = alpm_list_getdata(i); @@ -361,6 +362,7 @@ void display_targets(const alpm_list_t *syncpkgs) dispsize = alpm_pkg_get_size(pkg); size += dispsize; + dlsize += alpm_pkg_download_size(pkg, db_local); isize += alpm_pkg_get_isize(pkg); /* print the package size with the output if ShowSize option set */ @@ -381,6 +383,7 @@ void display_targets(const alpm_list_t *syncpkgs) mbsize = size / (1024.0 * 1024.0); mbisize = isize / (1024.0 * 1024.0); mbrsize = rsize / (1024.0 * 1024.0); + mbdlsize = dlsize / (1024.0 * 1024.0); /* start displaying information */ printf("\n"); @@ -390,28 +393,17 @@ void display_targets(const alpm_list_t *syncpkgs) printf("\n"); FREELIST(to_remove); - /* round up if size is really small */ - if(mbrsize < 0.1) { - mbrsize = 0.1; - } printf(_("Total Removed Size: %.2f MB\n"), mbrsize); } list_display(_("Targets:"), targets); printf("\n"); - /* round up if size is really small */ - if(mbsize < 0.1) { - mbsize = 0.1; - } - printf(_("Total Package Size: %.2f MB\n"), mbsize); + printf(_("Total Package Size: %.2f MB\n"), mbsize); + printf(_("Total Download Size: %.2f MB\n"), mbdlsize); /* TODO because all pkgs don't include isize, this is a crude hack */ if(mbisize > mbsize) { - /*round up if size is really small */ - if(mbisize < 0.1) { - mbisize = 0.1; - } printf(_("Total Installed Size: %.2f MB\n"), mbisize); } diff --git a/src/pacman/util.h b/src/pacman/util.h index f3171ca..876f817 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -47,7 +47,7 @@ char *strtoupper(char *str); char *strtrim(char *str); char *strreplace(const char *str, const char *needle, const char *replace); void list_display(const char *title, const alpm_list_t *list); -void display_targets(const alpm_list_t *syncpkgs); +void display_targets(const alpm_list_t *syncpkgs, pmdb_t *db_local); int yesno(char *fmt, ...); int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3))); int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...) __attribute__((format(printf,3,4))); -- 1.5.3.4
On Fri, Oct 19, 2007 at 01:17:49PM -0400, Nathan Jones wrote:
Also, is it just me, or do 78% of the pactests fail?
It's just you :) There are currently 7 pactests failing in git.
On 10/19/07, Nathan Jones <nathanj@insightbb.com> wrote:
Here are the updated patches for adding delta downloading to libalpm.
I had originally thought that if a delta could not be downloaded (due to md5sum or file deleted on the server), the package file should be downloaded instead. I decided not to do this because some users may be annoyed at seeing a 7MB download size but end up downloading 100MB openoffice package.
If the md5sum is not correct, the output is mangled a bit. I am not sure what causes this.
Proceed with installation? [Y/n] y :: Retrieving packages from test... wbox-3-1_to_4-1-i686... 7.9K 17.1M/s 00:00:00 [#####################] 100% wbox-4-1_to_4-2-i686... 0.4K 1087.1K/s 00:00:00 [#####################] 100% :: File wbox-4-1_to_4-2-i686.delta is corrupted. Do you want to delete it? [Y/n] checking delta integrity... error: failed to commit transaction (corrupted delta) Errors occurred, no packages were upgraded.
Also, is it just me, or do 78% of the pactests fail?
Are you running them using "make check"? As Xavier said, only 7 are failing right now as far as I know. When I have a problem like this, I tend to pick one of the simpler failing ones and run it with debug output, and then look at pactest.log (to run them, just use the command line from Makefile.am substituting where applicable). You can usually point out where the failure location is pretty quickly by doing this. -Dan
On Fri, Oct 19, 2007 at 01:10:52PM -0500, Dan McGee wrote:
On 10/19/07, Nathan Jones <nathanj@insightbb.com> wrote:
Also, is it just me, or do 78% of the pactests fail?
Are you running them using "make check"? As Xavier said, only 7 are failing right now as far as I know. When I have a problem like this, I tend to pick one of the simpler failing ones and run it with debug output, and then look at pactest.log (to run them, just use the command line from Makefile.am substituting where applicable). You can usually point out where the failure location is pretty quickly by doing this.
-Dan
make check works. The problem before was due to me thinking that the pacman binary would default to ../src/pacman/pacman. It works now that I am using the -p option.
participants (3)
-
Dan McGee
-
Nathan Jones
-
Xavier