package.c

Go to the documentation of this file.
00001 /*
00002  *  package.c
00003  *
00004  *  Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
00005  *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
00006  *  Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
00007  *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
00008  *
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00021  */
00022 
00023 #include "config.h"
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <limits.h>
00028 #include <string.h>
00029 #include <ctype.h>
00030 #include <errno.h>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <unistd.h>
00034 #include <locale.h> /* setlocale */
00035 
00036 /* libarchive */
00037 #include <archive.h>
00038 #include <archive_entry.h>
00039 
00040 /* libalpm */
00041 #include "package.h"
00042 #include "alpm_list.h"
00043 #include "log.h"
00044 #include "util.h"
00045 #include "error.h"
00046 #include "db.h"
00047 #include "cache.h"
00048 #include "delta.h"
00049 #include "handle.h"
00050 #include "deps.h"
00051 
00052 /** \addtogroup alpm_packages Package Functions
00053  * @brief Functions to manipulate libalpm packages
00054  * @{
00055  */
00056 
00057 /** Create a package from a file.
00058  * @param filename location of the package tarball
00059  * @param full whether to stop the load after metadata is read or continue
00060  *             through the full archive
00061  * @param pkg address of the package pointer
00062  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00063  */
00064 int SYMEXPORT alpm_pkg_load(const char *filename, unsigned short full,
00065         pmpkg_t **pkg)
00066 {
00067     _alpm_log(PM_LOG_FUNCTION, "enter alpm_pkg_load\n");
00068 
00069     /* Sanity checks */
00070     ASSERT(filename != NULL && strlen(filename) != 0,
00071             RET_ERR(PM_ERR_WRONG_ARGS, -1));
00072     ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
00073 
00074     *pkg = _alpm_pkg_load(filename, full);
00075     if(*pkg == NULL) {
00076         /* pm_errno is set by pkg_load */
00077         return(-1);
00078     }
00079 
00080     return(0);
00081 }
00082 
00083 /** Free a package.
00084  * @param pkg package pointer to free
00085  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00086  */
00087 int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)
00088 {
00089     _alpm_log(PM_LOG_FUNCTION, "enter alpm_pkg_free\n");
00090 
00091     ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
00092 
00093     /* Only free packages loaded in user space */
00094     if(pkg->origin != PKG_FROM_CACHE) {
00095         _alpm_pkg_free(pkg);
00096     }
00097 
00098     return(0);
00099 }
00100 
00101 /** Check the integrity (with md5) of a package from the sync cache.
00102  * @param pkg package pointer
00103  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00104  */
00105 int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
00106 {
00107     char *fpath;
00108     char *md5sum = NULL;
00109     int retval = 0;
00110 
00111     ALPM_LOG_FUNC;
00112 
00113     ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
00114     /* We only inspect packages from sync repositories */
00115     ASSERT(pkg->origin == PKG_FROM_CACHE, RET_ERR(PM_ERR_PKG_INVALID, -1));
00116     ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1));
00117 
00118     fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg));
00119     md5sum = alpm_get_md5sum(fpath);
00120 
00121     if(md5sum == NULL) {
00122         _alpm_log(PM_LOG_ERROR, _("could not get md5sum for package %s-%s\n"),
00123                             alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
00124         pm_errno = PM_ERR_NOT_A_FILE;
00125         retval = -1;
00126     } else {
00127         if(strcmp(md5sum, alpm_pkg_get_md5sum(pkg)) == 0) {
00128             _alpm_log(PM_LOG_DEBUG, "md5sums for package %s-%s match\n",
00129                                 alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
00130         } else {
00131             _alpm_log(PM_LOG_ERROR, _("md5sums do not match for package %s-%s\n"),
00132                                 alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
00133             pm_errno = PM_ERR_PKG_INVALID;
00134             retval = -1;
00135         }
00136     }
00137 
00138     FREE(fpath);
00139     FREE(md5sum);
00140 
00141     return(retval);
00142 }
00143 
00144 /** Compare versions.
00145  * @param ver1 first version
00146  * @param ver2 secont version
00147  * @return postive, 0 or negative if ver1 is less, equal or more
00148  * than ver2, respectively.
00149  */
00150 int SYMEXPORT alpm_pkg_vercmp(const char *ver1, const char *ver2)
00151 {
00152     ALPM_LOG_FUNC;
00153 
00154     return(_alpm_versioncmp(ver1, ver2));
00155 }
00156 
00157 const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)
00158 {
00159     ALPM_LOG_FUNC;
00160 
00161     /* Sanity checks */
00162     ASSERT(handle != NULL, return(NULL));
00163     ASSERT(pkg != NULL, return(NULL));
00164 
00165     if(pkg->filename == NULL || strlen(pkg->filename) == 0) {
00166         /* construct the file name, it's not in the desc file */
00167         if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00168             _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00169         }
00170         char buffer[PATH_MAX];
00171         if(pkg->arch && strlen(pkg->arch) > 0) {
00172             snprintf(buffer, PATH_MAX, "%s-%s-%s" PKGEXT,
00173                      pkg->name, pkg->version, pkg->arch);
00174         } else {
00175             snprintf(buffer, PATH_MAX, "%s-%s" PKGEXT,
00176                      pkg->name, pkg->version);
00177         }
00178         STRDUP(pkg->filename, buffer, RET_ERR(PM_ERR_MEMORY, NULL));
00179     }
00180 
00181     return pkg->filename;
00182 }
00183 
00184 const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)
00185 {
00186     ALPM_LOG_FUNC;
00187 
00188     /* Sanity checks */
00189     ASSERT(handle != NULL, return(NULL));
00190     ASSERT(pkg != NULL, return(NULL));
00191 
00192     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) {
00193         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
00194     }
00195     return pkg->name;
00196 }
00197 
00198 const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)
00199 {
00200     ALPM_LOG_FUNC;
00201 
00202     /* Sanity checks */
00203     ASSERT(handle != NULL, return(NULL));
00204     ASSERT(pkg != NULL, return(NULL));
00205 
00206     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) {
00207         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
00208     }
00209     return pkg->version;
00210 }
00211 
00212 const char SYMEXPORT *alpm_pkg_get_desc(pmpkg_t *pkg)
00213 {
00214     ALPM_LOG_FUNC;
00215 
00216     /* Sanity checks */
00217     ASSERT(handle != NULL, return(NULL));
00218     ASSERT(pkg != NULL, return(NULL));
00219 
00220     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00221         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00222     }
00223     return pkg->desc;
00224 }
00225 
00226 const char SYMEXPORT *alpm_pkg_get_url(pmpkg_t *pkg)
00227 {
00228     ALPM_LOG_FUNC;
00229 
00230     /* Sanity checks */
00231     ASSERT(handle != NULL, return(NULL));
00232     ASSERT(pkg != NULL, return(NULL));
00233 
00234     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00235         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00236     }
00237     return pkg->url;
00238 }
00239 
00240 time_t SYMEXPORT alpm_pkg_get_builddate(pmpkg_t *pkg)
00241 {
00242     ALPM_LOG_FUNC;
00243 
00244     /* Sanity checks */
00245     ASSERT(handle != NULL, return(0));
00246     ASSERT(pkg != NULL, return(0));
00247 
00248     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00249         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00250     }
00251     return pkg->builddate;
00252 }
00253 
00254 time_t SYMEXPORT alpm_pkg_get_installdate(pmpkg_t *pkg)
00255 {
00256     ALPM_LOG_FUNC;
00257 
00258     /* Sanity checks */
00259     ASSERT(handle != NULL, return(0));
00260     ASSERT(pkg != NULL, return(0));
00261 
00262     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00263         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00264     }
00265     return pkg->installdate;
00266 }
00267 
00268 const char SYMEXPORT *alpm_pkg_get_packager(pmpkg_t *pkg)
00269 {
00270     ALPM_LOG_FUNC;
00271 
00272     /* Sanity checks */
00273     ASSERT(handle != NULL, return(NULL));
00274     ASSERT(pkg != NULL, return(NULL));
00275 
00276     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00277         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00278     }
00279     return pkg->packager;
00280 }
00281 
00282 const char SYMEXPORT *alpm_pkg_get_md5sum(pmpkg_t *pkg)
00283 {
00284     ALPM_LOG_FUNC;
00285 
00286     /* Sanity checks */
00287     ASSERT(handle != NULL, return(NULL));
00288     ASSERT(pkg != NULL, return(NULL));
00289 
00290     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00291         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00292     }
00293     return pkg->md5sum;
00294 }
00295 
00296 const char SYMEXPORT *alpm_pkg_get_arch(pmpkg_t *pkg)
00297 {
00298     ALPM_LOG_FUNC;
00299 
00300     /* Sanity checks */
00301     ASSERT(handle != NULL, return(NULL));
00302     ASSERT(pkg != NULL, return(NULL));
00303 
00304     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00305         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00306     }
00307     return pkg->arch;
00308 }
00309 
00310 unsigned long SYMEXPORT alpm_pkg_get_size(pmpkg_t *pkg)
00311 {
00312     ALPM_LOG_FUNC;
00313 
00314     /* Sanity checks */
00315     ASSERT(handle != NULL, return(-1));
00316     ASSERT(pkg != NULL, return(-1));
00317 
00318     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00319         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00320     }
00321     return pkg->size;
00322 }
00323 
00324 unsigned long SYMEXPORT alpm_pkg_get_isize(pmpkg_t *pkg)
00325 {
00326     ALPM_LOG_FUNC;
00327 
00328     /* Sanity checks */
00329     ASSERT(handle != NULL, return(-1));
00330     ASSERT(pkg != NULL, return(-1));
00331 
00332     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00333         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00334     }
00335     return pkg->isize;
00336 }
00337 
00338 pmpkgreason_t SYMEXPORT alpm_pkg_get_reason(pmpkg_t *pkg)
00339 {
00340     ALPM_LOG_FUNC;
00341 
00342     /* Sanity checks */
00343     ASSERT(handle != NULL, return(-1));
00344     ASSERT(pkg != NULL, return(-1));
00345 
00346     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00347         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00348     }
00349     return pkg->reason;
00350 }
00351 
00352 alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(pmpkg_t *pkg)
00353 {
00354     ALPM_LOG_FUNC;
00355 
00356     /* Sanity checks */
00357     ASSERT(handle != NULL, return(NULL));
00358     ASSERT(pkg != NULL, return(NULL));
00359 
00360     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00361         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00362     }
00363     return pkg->licenses;
00364 }
00365 
00366 alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)
00367 {
00368     ALPM_LOG_FUNC;
00369 
00370     /* Sanity checks */
00371     ASSERT(handle != NULL, return(NULL));
00372     ASSERT(pkg != NULL, return(NULL));
00373 
00374     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00375         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00376     }
00377     return pkg->groups;
00378 }
00379 
00380 alpm_list_t SYMEXPORT *alpm_pkg_get_depends(pmpkg_t *pkg)
00381 {
00382     ALPM_LOG_FUNC;
00383 
00384     /* Sanity checks */
00385     ASSERT(handle != NULL, return(NULL));
00386     ASSERT(pkg != NULL, return(NULL));
00387 
00388     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
00389         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
00390     }
00391     return pkg->depends;
00392 }
00393 
00394 alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(pmpkg_t *pkg)
00395 {
00396     ALPM_LOG_FUNC;
00397 
00398     /* Sanity checks */
00399     ASSERT(handle != NULL, return(NULL));
00400     ASSERT(pkg != NULL, return(NULL));
00401 
00402     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
00403         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
00404     }
00405     return pkg->optdepends;
00406 }
00407 
00408 alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(pmpkg_t *pkg)
00409 {
00410     ALPM_LOG_FUNC;
00411 
00412     /* Sanity checks */
00413     ASSERT(handle != NULL, return(NULL));
00414     ASSERT(pkg != NULL, return(NULL));
00415 
00416     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
00417         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
00418     }
00419     return pkg->conflicts;
00420 }
00421 
00422 alpm_list_t SYMEXPORT *alpm_pkg_get_provides(pmpkg_t *pkg)
00423 {
00424     ALPM_LOG_FUNC;
00425 
00426     /* Sanity checks */
00427     ASSERT(handle != NULL, return(NULL));
00428     ASSERT(pkg != NULL, return(NULL));
00429 
00430     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
00431         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
00432     }
00433     return pkg->provides;
00434 }
00435 
00436 alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
00437 {
00438     ALPM_LOG_FUNC;
00439 
00440     /* Sanity checks */
00441     ASSERT(handle != NULL, return(NULL));
00442     ASSERT(pkg != NULL, return(NULL));
00443 
00444     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DELTAS)) {
00445         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS);
00446     }
00447     return pkg->deltas;
00448 }
00449 
00450 alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
00451 {
00452     ALPM_LOG_FUNC;
00453 
00454     /* Sanity checks */
00455     ASSERT(handle != NULL, return(NULL));
00456     ASSERT(pkg != NULL, return(NULL));
00457 
00458     if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
00459         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
00460     }
00461     return pkg->replaces;
00462 }
00463 
00464 alpm_list_t SYMEXPORT *alpm_pkg_get_files(pmpkg_t *pkg)
00465 {
00466     ALPM_LOG_FUNC;
00467 
00468     /* Sanity checks */
00469     ASSERT(handle != NULL, return(NULL));
00470     ASSERT(pkg != NULL, return(NULL));
00471 
00472     if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
00473          && !(pkg->infolevel & INFRQ_FILES)) {
00474         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
00475     }
00476     return pkg->files;
00477 }
00478 
00479 alpm_list_t SYMEXPORT *alpm_pkg_get_backup(pmpkg_t *pkg)
00480 {
00481     ALPM_LOG_FUNC;
00482 
00483     /* Sanity checks */
00484     ASSERT(handle != NULL, return(NULL));
00485     ASSERT(pkg != NULL, return(NULL));
00486 
00487     if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
00488          && !(pkg->infolevel & INFRQ_FILES)) {
00489         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
00490     }
00491     return pkg->backup;
00492 }
00493 
00494 /**
00495  * Open a package changelog for reading. Similar to fopen in functionality,
00496  * except that the returned 'file stream' could really be from an archive
00497  * as well as from the database.
00498  * @param pkg the package to read the changelog of (either file or db)
00499  * @return a 'file stream' to the package changelog
00500  */
00501 void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
00502 {
00503     ALPM_LOG_FUNC;
00504 
00505     /* Sanity checks */
00506     ASSERT(handle != NULL, return(NULL));
00507     ASSERT(pkg != NULL, return(NULL));
00508 
00509     if(pkg->origin == PKG_FROM_CACHE) {
00510         char clfile[PATH_MAX];
00511         snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
00512                 alpm_option_get_dbpath(),
00513                 alpm_db_get_name(handle->db_local),
00514                 alpm_pkg_get_name(pkg),
00515                 alpm_pkg_get_version(pkg));
00516         return fopen(clfile, "r");
00517     } else if(pkg->origin == PKG_FROM_FILE) {
00518         struct archive *archive = NULL;
00519         struct archive_entry *entry;
00520         const char *pkgfile = pkg->origin_data.file;
00521         int ret = ARCHIVE_OK;
00522 
00523         if((archive = archive_read_new()) == NULL) {
00524             RET_ERR(PM_ERR_LIBARCHIVE_ERROR, NULL);
00525         }
00526 
00527         archive_read_support_compression_all(archive);
00528         archive_read_support_format_all(archive);
00529 
00530         if (archive_read_open_filename(archive, pkgfile,
00531                     ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
00532             RET_ERR(PM_ERR_PKG_OPEN, NULL);
00533         }
00534 
00535         while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
00536             const char *entry_name = archive_entry_pathname(entry);
00537 
00538             if(strcmp(entry_name, ".CHANGELOG") == 0) {
00539                 return(archive);
00540             }
00541         }
00542         /* we didn't find a changelog */
00543         archive_read_finish(archive);
00544         errno = ENOENT;
00545     }
00546     return(NULL);
00547 }
00548 
00549 /**
00550  * Read data from an open changelog 'file stream'. Similar to fread in
00551  * functionality, this function takes a buffer and amount of data to read.
00552  * @param ptr a buffer to fill with raw changelog data
00553  * @param size the size of the buffer
00554  * @param pkg the package that the changelog is being read from
00555  * @param fp a 'file stream' to the package changelog
00556  * @return the number of characters read, or 0 if there is no more data
00557  */
00558 size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,
00559         const pmpkg_t *pkg, const void *fp)
00560 {
00561     size_t ret = 0;
00562     if(pkg->origin == PKG_FROM_CACHE) {
00563         ret = fread(ptr, 1, size, (FILE*)fp);
00564     } else if(pkg->origin == PKG_FROM_FILE) {
00565         ret = archive_read_data((struct archive*)fp, ptr, size);
00566     }
00567     return(ret);
00568 }
00569 
00570 /*
00571 int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
00572 {
00573     int ret = 0;
00574     if(pkg->origin == PKG_FROM_CACHE) {
00575         ret = feof((FILE*)fp);
00576     } else if(pkg->origin == PKG_FROM_FILE) {
00577         // note: this doesn't quite work, no feof in libarchive
00578         ret = archive_read_data((struct archive*)fp, NULL, 0);
00579     }
00580     return(ret);
00581 }
00582 */
00583 
00584 /**
00585  * Close a package changelog for reading. Similar to fclose in functionality,
00586  * except that the 'file stream' could really be from an archive as well as
00587  * from the database.
00588  * @param pkg the package that the changelog was read from
00589  * @param fp a 'file stream' to the package changelog
00590  * @return whether closing the package changelog stream was successful
00591  */
00592 int SYMEXPORT alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp)
00593 {
00594     int ret = 0;
00595     if(pkg->origin == PKG_FROM_CACHE) {
00596         ret = fclose((FILE*)fp);
00597     } else if(pkg->origin == PKG_FROM_FILE) {
00598         ret = archive_read_finish((struct archive *)fp);
00599     }
00600     return(ret);
00601 }
00602 
00603 unsigned short SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg)
00604 {
00605     ALPM_LOG_FUNC;
00606 
00607     /* Sanity checks */
00608     ASSERT(handle != NULL, return(-1));
00609     ASSERT(pkg != NULL, return(-1));
00610 
00611     if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
00612          && !(pkg->infolevel & INFRQ_SCRIPTLET)) {
00613         _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);
00614     }
00615     return pkg->scriptlet;
00616 }
00617 
00618 /**
00619  * @brief Compute the packages requiring a given package.
00620  * @param pkg a package
00621  * @return the list of packages requiring pkg
00622  *
00623  * A depends on B through n depends <=> A listed in B's requiredby n times
00624  * n == 0 or 1 in almost all cases */
00625 alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(pmpkg_t *pkg)
00626 {
00627     const alpm_list_t *i, *j;
00628     alpm_list_t *reqs = NULL;
00629 
00630     pmdb_t *localdb = alpm_option_get_localdb();
00631     for(i = _alpm_db_get_pkgcache(localdb); i; i = i->next) {
00632         if(!i->data) {
00633             continue;
00634         }
00635         pmpkg_t *cachepkg = i->data;
00636         const char *cachepkgname = alpm_pkg_get_name(cachepkg);
00637 
00638         for(j = alpm_pkg_get_depends(cachepkg); j; j = j->next) {
00639             pmdepend_t *dep = j->data;
00640 
00641             if(alpm_depcmp(pkg, dep)) {
00642                 _alpm_log(PM_LOG_DEBUG, "adding '%s' in requiredby field for '%s'\n",
00643                           cachepkgname, pkg->name);
00644                 reqs = alpm_list_add(reqs, strdup(cachepkgname));
00645             }
00646         }
00647     }
00648     return(reqs);
00649 }
00650 
00651 /** @} */
00652 
00653 /* this function was taken from rpm 4.0.4 and rewritten */
00654 int _alpm_versioncmp(const char *a, const char *b)
00655 {
00656     char str1[64], str2[64];
00657     char *ptr1, *ptr2;
00658     char *one, *two;
00659     char *rel1 = NULL, *rel2 = NULL;
00660     char oldch1, oldch2;
00661     int is1num, is2num;
00662     int rc;
00663 
00664     ALPM_LOG_FUNC;
00665 
00666     if(!strcmp(a,b)) {
00667         return(0);
00668     }
00669 
00670     strncpy(str1, a, 64);
00671     str1[63] = 0;
00672     strncpy(str2, b, 64);
00673     str2[63] = 0;
00674 
00675     /* lose the release number */
00676     for(one = str1; *one && *one != '-'; one++);
00677     if(one) {
00678         *one = '\0';
00679         rel1 = ++one;
00680     }
00681     for(two = str2; *two && *two != '-'; two++);
00682     if(two) {
00683         *two = '\0';
00684         rel2 = ++two;
00685     }
00686 
00687     one = str1;
00688     two = str2;
00689 
00690     while(*one || *two) {
00691         while(*one && !isalnum((int)*one)) one++;
00692         while(*two && !isalnum((int)*two)) two++;
00693 
00694         ptr1 = one;
00695         ptr2 = two;
00696 
00697         /* find the next segment for each string */
00698         if(isdigit((int)*ptr1)) {
00699             is1num = 1;
00700             while(*ptr1 && isdigit((int)*ptr1)) ptr1++;
00701         } else {
00702             is1num = 0;
00703             while(*ptr1 && isalpha((int)*ptr1)) ptr1++;
00704         }
00705         if(isdigit((int)*ptr2)) {
00706             is2num = 1;
00707             while(*ptr2 && isdigit((int)*ptr2)) ptr2++;
00708         } else {
00709             is2num = 0;
00710             while(*ptr2 && isalpha((int)*ptr2)) ptr2++;
00711         }
00712 
00713         oldch1 = *ptr1;
00714         *ptr1 = '\0';
00715         oldch2 = *ptr2;
00716         *ptr2 = '\0';
00717 
00718         /* see if we ran out of segments on one string */
00719         if(one == ptr1 && two != ptr2) {
00720             return(is2num ? -1 : 1);
00721         }
00722         if(one != ptr1 && two == ptr2) {
00723             return(is1num ? 1 : -1);
00724         }
00725 
00726         /* see if we have a type mismatch (ie, one is alpha and one is digits) */
00727         if(is1num && !is2num) return(1);
00728         if(!is1num && is2num) return(-1);
00729 
00730         if(is1num) while(*one == '0') one++;
00731         if(is2num) while(*two == '0') two++;
00732 
00733         rc = strverscmp(one, two);
00734         if(rc) return(rc);
00735 
00736         *ptr1 = oldch1;
00737         *ptr2 = oldch2;
00738         one = ptr1;
00739         two = ptr2;
00740     }
00741 
00742     if((!*one) && (!*two)) {
00743         /* compare release numbers */
00744         if(rel1 && rel2 && strlen(rel1) && strlen(rel2)) return(_alpm_versioncmp(rel1, rel2));
00745         return(0);
00746     }
00747 
00748     return(*one ? 1 : -1);
00749 }
00750 
00751 
00752 pmpkg_t *_alpm_pkg_new(const char *name, const char *version)
00753 {
00754     pmpkg_t* pkg;
00755 
00756     ALPM_LOG_FUNC;
00757 
00758     CALLOC(pkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
00759 
00760     if(name) {
00761         STRDUP(pkg->name, name, RET_ERR(PM_ERR_MEMORY, pkg));
00762     }
00763 
00764     if(version) {
00765         STRDUP(pkg->version, version, RET_ERR(PM_ERR_MEMORY, pkg));
00766     }
00767 
00768     return(pkg);
00769 }
00770 
00771 pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
00772 {
00773     pmpkg_t *newpkg;
00774     alpm_list_t *i;
00775 
00776     ALPM_LOG_FUNC;
00777 
00778     CALLOC(newpkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
00779 
00780     STRDUP(newpkg->filename, pkg->filename, RET_ERR(PM_ERR_MEMORY, newpkg));
00781     STRDUP(newpkg->name, pkg->name, RET_ERR(PM_ERR_MEMORY, newpkg));
00782     STRDUP(newpkg->version, pkg->version, RET_ERR(PM_ERR_MEMORY, newpkg));
00783     STRDUP(newpkg->desc, pkg->desc, RET_ERR(PM_ERR_MEMORY, newpkg));
00784     STRDUP(newpkg->url, pkg->url, RET_ERR(PM_ERR_MEMORY, newpkg));
00785     newpkg->builddate = pkg->builddate;
00786     newpkg->installdate = pkg->installdate;
00787     STRDUP(newpkg->packager, pkg->packager, RET_ERR(PM_ERR_MEMORY, newpkg));
00788     STRDUP(newpkg->md5sum, pkg->md5sum, RET_ERR(PM_ERR_MEMORY, newpkg));
00789     STRDUP(newpkg->arch, pkg->arch, RET_ERR(PM_ERR_MEMORY, newpkg));
00790     newpkg->size = pkg->size;
00791     newpkg->isize = pkg->isize;
00792     newpkg->scriptlet = pkg->scriptlet;
00793     newpkg->force = pkg->force;
00794     newpkg->reason = pkg->reason;
00795 
00796     newpkg->licenses   = alpm_list_strdup(alpm_pkg_get_licenses(pkg));
00797     newpkg->replaces   = alpm_list_strdup(alpm_pkg_get_replaces(pkg));
00798     newpkg->groups     = alpm_list_strdup(alpm_pkg_get_groups(pkg));
00799     newpkg->files      = alpm_list_strdup(alpm_pkg_get_files(pkg));
00800     newpkg->backup     = alpm_list_strdup(alpm_pkg_get_backup(pkg));
00801     for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) {
00802         newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data));
00803     }
00804     newpkg->optdepends = alpm_list_strdup(alpm_pkg_get_optdepends(pkg));
00805     newpkg->conflicts  = alpm_list_strdup(alpm_pkg_get_conflicts(pkg));
00806     newpkg->provides   = alpm_list_strdup(alpm_pkg_get_provides(pkg));
00807     newpkg->deltas     = alpm_list_copy_data(alpm_pkg_get_deltas(pkg),
00808                                                                                      sizeof(pmdelta_t));
00809 
00810     /* internal */
00811     newpkg->origin = pkg->origin;
00812     if(newpkg->origin == PKG_FROM_FILE) {
00813         newpkg->origin_data.file = strdup(pkg->origin_data.file);
00814     } else {
00815         newpkg->origin_data.db = pkg->origin_data.db;
00816     }
00817     newpkg->infolevel = pkg->infolevel;
00818 
00819     return(newpkg);
00820 }
00821 
00822 void _alpm_pkg_free(pmpkg_t *pkg)
00823 {
00824     ALPM_LOG_FUNC;
00825 
00826     if(pkg == NULL) {
00827         return;
00828     }
00829 
00830     FREE(pkg->filename);
00831     FREE(pkg->name);
00832     FREE(pkg->version);
00833     FREE(pkg->desc);
00834     FREE(pkg->url);
00835     FREE(pkg->packager);
00836     FREE(pkg->md5sum);
00837     FREE(pkg->arch);
00838     FREELIST(pkg->licenses);
00839     FREELIST(pkg->replaces);
00840     FREELIST(pkg->groups);
00841     FREELIST(pkg->files);
00842     FREELIST(pkg->backup);
00843     alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free);
00844     alpm_list_free(pkg->depends);
00845     FREELIST(pkg->optdepends);
00846     FREELIST(pkg->conflicts);
00847     FREELIST(pkg->provides);
00848     FREELIST(pkg->deltas);
00849 
00850     if(pkg->origin == PKG_FROM_FILE) {
00851         FREE(pkg->origin_data.file);
00852     }
00853     FREE(pkg);
00854 }
00855 
00856 /* Is pkgB an upgrade for pkgA ? */
00857 int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg)