delta.c

Go to the documentation of this file.
00001 /*
00002  *  delta.c
00003  *
00004  *  Copyright (c) 2007 by Judd Vinet <jvinet@zeroflux.org>
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "config.h"
00021 
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 /* libalpm */
00026 #include "delta.h"
00027 #include "error.h"
00028 #include "util.h"
00029 #include "log.h"
00030 #include "alpm_list.h"
00031 #include "alpm.h"
00032 
00033 /** \addtogroup alpm_deltas Delta Functions
00034  * @brief Functions to manipulate libalpm deltas
00035  * @{
00036  */
00037 
00038 const char SYMEXPORT *alpm_delta_get_from(pmdelta_t *delta)
00039 {
00040     ALPM_LOG_FUNC;
00041 
00042     /* Sanity checks */
00043     ASSERT(delta != NULL, return(NULL));
00044 
00045     return(delta->from);
00046 }
00047 
00048 const char SYMEXPORT *alpm_delta_get_to(pmdelta_t *delta)
00049 {
00050     ALPM_LOG_FUNC;
00051 
00052     /* Sanity checks */
00053     ASSERT(delta != NULL, return(NULL));
00054 
00055     return(delta->to);
00056 }
00057 
00058 unsigned long SYMEXPORT alpm_delta_get_size(pmdelta_t *delta)
00059 {
00060     ALPM_LOG_FUNC;
00061 
00062     /* Sanity checks */
00063     ASSERT(delta != NULL, return(-1));
00064 
00065     return(delta->size);
00066 }
00067 
00068 const char SYMEXPORT *alpm_delta_get_filename(pmdelta_t *delta)
00069 {
00070     ALPM_LOG_FUNC;
00071 
00072     /* Sanity checks */
00073     ASSERT(delta != NULL, return(NULL));
00074 
00075     return(delta->filename);
00076 }
00077 
00078 const char SYMEXPORT *alpm_delta_get_md5sum(pmdelta_t *delta)
00079 {
00080     ALPM_LOG_FUNC;
00081 
00082     /* Sanity checks */
00083     ASSERT(delta != NULL, return(NULL));
00084 
00085     return(delta->md5sum);
00086 }
00087 
00088 /** @} */
00089 
00090 /** Calculates the combined size of a list of delta files.
00091  *
00092  * @param deltas the list of pmdelta_t * objects
00093  *
00094  * @return the combined size
00095  */
00096 unsigned long _alpm_delta_path_size(alpm_list_t *deltas)
00097 {
00098     unsigned long sum = 0;
00099     alpm_list_t *dlts = deltas;
00100 
00101     while(dlts) {
00102         pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts);
00103         sum += d->size;
00104 
00105         dlts = alpm_list_next(dlts);
00106     }
00107 
00108     return(sum);
00109 }
00110 
00111 /** Calculates the combined size of a list of delta files that are not
00112  * in the cache.
00113  *
00114  * @param deltas the list of pmdelta_t * objects
00115  *
00116  * @return the combined size
00117  */
00118 unsigned long _alpm_delta_path_size_uncached(alpm_list_t *deltas)
00119 {
00120     unsigned long sum = 0;
00121     alpm_list_t *dlts = deltas;
00122 
00123     while(dlts) {
00124         pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts);
00125         char *fname = _alpm_filecache_find(d->filename);
00126 
00127         if(!fname) {
00128             sum += d->size;
00129         }
00130 
00131         FREE(fname);
00132 
00133         dlts = alpm_list_next(dlts);
00134     }
00135 
00136     return(sum);
00137 }
00138 
00139 /** Calculates the shortest path from one version to another.
00140  *
00141  * The shortest path is defined as the path with the smallest combined
00142  * size, not the length of the path.
00143  *
00144  * The algorithm is based on Dijkstra's shortest path algorithm.
00145  *
00146  * @param deltas the list of pmdelta_t * objects that a package has
00147  * @param from the version to start from
00148  * @param to the version to end at
00149  * @param path the current path
00150  *
00151  * @return the list of pmdelta_t * objects that has the smallest size.
00152  * NULL (the empty list) is returned if there is no path between the
00153  * versions.
00154  */
00155 static alpm_list_t *shortest_delta_path(alpm_list_t *deltas,
00156         const char *from, const char *to, alpm_list_t *path)
00157 {
00158     alpm_list_t *d;
00159     alpm_list_t *shortest = NULL;
00160 
00161     /* Found the 'to' version, this is a good path so return it. */
00162     if(strcmp(from, to) == 0) {
00163         return(path);
00164     }
00165 
00166     for(d = deltas; d; d = alpm_list_next(d)) {
00167         pmdelta_t *v = alpm_list_getdata(d);
00168 
00169         /* If this vertex has already been visited in the path, go to the
00170          * next vertex. */
00171         if(alpm_list_find_ptr(path, v)) {
00172             continue;
00173         }
00174 
00175         /* Once we find a vertex that starts at the 'from' version,
00176          * recursively find the shortest path using the 'to' version of this
00177          * current vertex as the 'from' version in the function call. */
00178         if(strcmp(v->from, from) == 0) {
00179             alpm_list_t *newpath = alpm_list_copy(path);
00180             newpath = alpm_list_add(newpath, v);
00181             newpath = shortest_delta_path(deltas, v->to, to, newpath);
00182 
00183             if(newpath != NULL) {
00184                 /* The path returned works, now use it unless there is already a
00185                  * shorter path found. */
00186                 if(shortest == NULL) {
00187                     shortest = newpath;
00188                 } else if(_alpm_delta_path_size(shortest) > _alpm_delta_path_size(newpath)) {
00189                     alpm_list_free(shortest);
00190                     shortest = newpath;
00191                 } else {
00192                     alpm_list_free(newpath);
00193                 }
00194             }
00195         }
00196     }
00197 
00198     alpm_list_free(path);
00199 
00200     return(shortest);
00201 }
00202 
00203 /** Calculates the shortest path from one version to another.
00204  *
00205  * The shortest path is defined as the path with the smallest combined
00206  * size, not the length of the path.
00207  *
00208  * @param deltas the list of pmdelta_t * objects that a package has
00209  * @param from the version to start from
00210  * @param to the version to end at
00211  *
00212  * @return the list of pmdelta_t * objects that has the smallest size.
00213  * NULL (the empty list) is returned if there is no path between the
00214  * versions.
00215  */
00216 alpm_list_t *_alpm_shortest_delta_path(alpm_list_t *deltas, const char *from,
00217         const char *to)
00218 {
00219     alpm_list_t *path = NULL;
00220 
00221     path = shortest_delta_path(deltas, from, to, path);
00222 
00223     return(path);
00224 }
00225 
00226 /** Parses the string representation of a pmdelta_t object.
00227  *
00228  * This function assumes that the string is in the correct format.
00229  *
00230  * @param line the string to parse
00231  *
00232  * @return A pointer to the new pmdelta_t object
00233  */
00234 pmdelta_t *_alpm_delta_parse(char *line)
00235 {
00236     pmdelta_t *delta;
00237     char *tmp = line, *tmp2;
00238 
00239     CALLOC(delta, 1, sizeof(pmdelta_t), RET_ERR(PM_ERR_MEMORY, NULL));
00240 
00241     tmp2 = tmp;
00242     tmp = strchr(tmp, ' ');
00243     *(tmp++) = '\0';
00244     strncpy(delta->from, tmp2, DLT_VERSION_LEN);
00245 
00246     tmp2 = tmp;
00247     tmp = strchr(tmp, ' ');
00248     *(tmp++) = '\0';
00249     strncpy(delta->to, tmp2, DLT_VERSION_LEN);
00250 
00251     tmp2 = tmp;
00252     tmp = strchr(tmp, ' ');
00253     *(tmp++) = '\0';
00254     delta->size = atol(tmp2);
00255 
00256     tmp2 = tmp;
00257     tmp = strchr(tmp, ' ');
00258     *(tmp++) = '\0';
00259     strncpy(delta->filename, tmp2, DLT_FILENAME_LEN);
00260 
00261     strncpy(delta->md5sum, tmp, DLT_MD5SUM_LEN);
00262 
00263     return(delta);
00264 }
00265 
00266 /* vim: set ts=2 sw=2 noet: */

Generated on Mon Jan 14 23:53:40 2008 for libalpm by  doxygen 1.5.4