libalpm
Arch Linux Package Manager Library
db.c
Go to the documentation of this file.
00001 /*
00002  *  db.c
00003  *
00004  *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
00005  *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
00006  *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
00007  *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
00008  *  Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
00009  *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
00010  *
00011  *  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023  */
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <regex.h>
00029 
00030 /* libalpm */
00031 #include "db.h"
00032 #include "alpm_list.h"
00033 #include "log.h"
00034 #include "util.h"
00035 #include "handle.h"
00036 #include "alpm.h"
00037 #include "package.h"
00038 #include "group.h"
00039 
00040 /** \addtogroup alpm_databases Database Functions
00041  * @brief Functions to query and manipulate the database of libalpm
00042  * @{
00043  */
00044 
00045 /** Register a sync database of packages. */
00046 alpm_db_t SYMEXPORT *alpm_db_register_sync(alpm_handle_t *handle,
00047         const char *treename, alpm_siglevel_t level)
00048 {
00049     /* Sanity checks */
00050     CHECK_HANDLE(handle, return NULL);
00051     ASSERT(treename != NULL && strlen(treename) != 0,
00052             RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL));
00053     /* Do not register a database if a transaction is on-going */
00054     ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, NULL));
00055 
00056     return _alpm_db_register_sync(handle, treename, level);
00057 }
00058 
00059 /* Helper function for alpm_db_unregister{_all} */
00060 void _alpm_db_unregister(alpm_db_t *db)
00061 {
00062     if(db == NULL) {
00063         return;
00064     }
00065 
00066     _alpm_log(db->handle, ALPM_LOG_DEBUG, "unregistering database '%s'\n", db->treename);
00067     _alpm_db_free(db);
00068 }
00069 
00070 /** Unregister all package databases. */
00071 int SYMEXPORT alpm_db_unregister_all(alpm_handle_t *handle)
00072 {
00073     alpm_list_t *i;
00074     alpm_db_t *db;
00075 
00076     /* Sanity checks */
00077     CHECK_HANDLE(handle, return -1);
00078     /* Do not unregister a database if a transaction is on-going */
00079     ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, -1));
00080 
00081     /* unregister all sync dbs */
00082     for(i = handle->dbs_sync; i; i = i->next) {
00083         db = i->data;
00084         db->ops->unregister(db);
00085         i->data = NULL;
00086     }
00087     FREELIST(handle->dbs_sync);
00088     return 0;
00089 }
00090 
00091 /** Unregister a package database. */
00092 int SYMEXPORT alpm_db_unregister(alpm_db_t *db)
00093 {
00094     int found = 0;
00095     alpm_handle_t *handle;
00096 
00097     /* Sanity checks */
00098     ASSERT(db != NULL, return -1);
00099     /* Do not unregister a database if a transaction is on-going */
00100     handle = db->handle;
00101     handle->pm_errno = 0;
00102     ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, -1));
00103 
00104     if(db == handle->db_local) {
00105         handle->db_local = NULL;
00106         found = 1;
00107     } else {
00108         /* Warning : this function shouldn't be used to unregister all sync
00109          * databases by walking through the list returned by
00110          * alpm_option_get_syncdbs, because the db is removed from that list here.
00111          */
00112         void *data;
00113         handle->dbs_sync = alpm_list_remove(handle->dbs_sync,
00114                 db, _alpm_db_cmp, &data);
00115         if(data) {
00116             found = 1;
00117         }
00118     }
00119 
00120     if(!found) {
00121         RET_ERR(handle, ALPM_ERR_DB_NOT_FOUND, -1);
00122     }
00123 
00124     db->ops->unregister(db);
00125     return 0;
00126 }
00127 
00128 /** Get the serverlist of a database. */
00129 alpm_list_t SYMEXPORT *alpm_db_get_servers(const alpm_db_t *db)
00130 {
00131     ASSERT(db != NULL, return NULL);
00132     return db->servers;
00133 }
00134 
00135 /** Set the serverlist of a database. */
00136 int SYMEXPORT alpm_db_set_servers(alpm_db_t *db, alpm_list_t *servers)
00137 {
00138     ASSERT(db != NULL, return -1);
00139     if(db->servers) FREELIST(db->servers);
00140     db->servers = servers;
00141     return 0;
00142 }
00143 
00144 static char *sanitize_url(const char *url)
00145 {
00146     char *newurl;
00147     size_t len = strlen(url);
00148 
00149     STRDUP(newurl, url, return NULL);
00150     /* strip the trailing slash if one exists */
00151     if(newurl[len - 1] == '/') {
00152         newurl[len - 1] = '\0';
00153     }
00154     return newurl;
00155 }
00156 
00157 /** Add a download server to a database.
00158  * @param db database pointer
00159  * @param url url of the server
00160  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00161  */
00162 int SYMEXPORT alpm_db_add_server(alpm_db_t *db, const char *url)
00163 {
00164     char *newurl;
00165 
00166     /* Sanity checks */
00167     ASSERT(db != NULL, return -1);
00168     db->handle->pm_errno = 0;
00169     ASSERT(url != NULL && strlen(url) != 0, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
00170 
00171     newurl = sanitize_url(url);
00172     if(!newurl) {
00173         return -1;
00174     }
00175     db->servers = alpm_list_add(db->servers, newurl);
00176     _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding new server URL to database '%s': %s\n",
00177             db->treename, newurl);
00178 
00179     return 0;
00180 }
00181 
00182 /** Remove a download server from a database.
00183  * @param db database pointer
00184  * @param url url of the server
00185  * @return 0 on success, 1 on server not present,
00186  * -1 on error (pm_errno is set accordingly)
00187  */
00188 int SYMEXPORT alpm_db_remove_server(alpm_db_t *db, const char *url)
00189 {
00190     char *newurl, *vdata = NULL;
00191 
00192     /* Sanity checks */
00193     ASSERT(db != NULL, return -1);
00194     db->handle->pm_errno = 0;
00195     ASSERT(url != NULL && strlen(url) != 0, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
00196 
00197     newurl = sanitize_url(url);
00198     if(!newurl) {
00199         return -1;
00200     }
00201     db->servers = alpm_list_remove_str(db->servers, newurl, &vdata);
00202     free(newurl);
00203     if(vdata) {
00204         _alpm_log(db->handle, ALPM_LOG_DEBUG, "removed server URL from database '%s': %s\n",
00205                 db->treename, newurl);
00206         free(vdata);
00207         return 0;
00208     }
00209 
00210     return 1;
00211 }
00212 
00213 /** Get the name of a package database. */
00214 const char SYMEXPORT *alpm_db_get_name(const alpm_db_t *db)
00215 {
00216     ASSERT(db != NULL, return NULL);
00217     return db->treename;
00218 }
00219 
00220 /** Get the signature verification level for a database. */
00221 alpm_siglevel_t SYMEXPORT alpm_db_get_siglevel(alpm_db_t *db)
00222 {
00223     ASSERT(db != NULL, return -1);
00224     if(db->siglevel & ALPM_SIG_USE_DEFAULT) {
00225         return db->handle->siglevel;
00226     } else {
00227         return db->siglevel;
00228     }
00229 }
00230 
00231 /** Check the validity of a database. */
00232 int SYMEXPORT alpm_db_get_valid(alpm_db_t *db)
00233 {
00234     ASSERT(db != NULL, return -1);
00235     db->handle->pm_errno = 0;
00236     return db->ops->validate(db);
00237 }
00238 
00239 /** Get a package entry from a package database. */
00240 alpm_pkg_t SYMEXPORT *alpm_db_get_pkg(alpm_db_t *db, const char *name)
00241 {
00242     alpm_pkg_t *pkg;
00243     ASSERT(db != NULL, return NULL);
00244     db->handle->pm_errno = 0;
00245     ASSERT(name != NULL && strlen(name) != 0,
00246             RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, NULL));
00247 
00248     pkg = _alpm_db_get_pkgfromcache(db, name);
00249     if(!pkg) {
00250         RET_ERR(db->handle, ALPM_ERR_PKG_NOT_FOUND, NULL);
00251     }
00252     return pkg;
00253 }
00254 
00255 /** Get the package cache of a package database. */
00256 alpm_list_t SYMEXPORT *alpm_db_get_pkgcache(alpm_db_t *db)
00257 {
00258     ASSERT(db != NULL, return NULL);
00259     db->handle->pm_errno = 0;
00260     return _alpm_db_get_pkgcache(db);
00261 }
00262 
00263 /** Get a group entry from a package database. */
00264 alpm_group_t SYMEXPORT *alpm_db_readgroup(alpm_db_t *db, const char *name)
00265 {
00266     ASSERT(db != NULL, return NULL);
00267     db->handle->pm_errno = 0;
00268     ASSERT(name != NULL && strlen(name) != 0,
00269             RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, NULL));
00270 
00271     return _alpm_db_get_groupfromcache(db, name);
00272 }
00273 
00274 /** Get the group cache of a package database. */
00275 alpm_list_t SYMEXPORT *alpm_db_get_groupcache(alpm_db_t *db)
00276 {
00277     ASSERT(db != NULL, return NULL);
00278     db->handle->pm_errno = 0;
00279 
00280     return _alpm_db_get_groupcache(db);
00281 }
00282 
00283 /** Searches a database. */
00284 alpm_list_t SYMEXPORT *alpm_db_search(alpm_db_t *db, const alpm_list_t* needles)
00285 {
00286     ASSERT(db != NULL, return NULL);
00287     db->handle->pm_errno = 0;
00288 
00289     return _alpm_db_search(db, needles);
00290 }
00291 
00292 /** Set install reason for a package in db. */
00293 int SYMEXPORT alpm_db_set_pkgreason(alpm_handle_t *handle, alpm_pkg_t *pkg,
00294         alpm_pkgreason_t reason)
00295 {
00296     CHECK_HANDLE(handle, return -1);
00297     ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
00298     ASSERT(pkg->origin == PKG_FROM_LOCALDB,
00299             RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
00300     ASSERT(pkg->origin_data.db == handle->db_local,
00301             RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
00302 
00303     _alpm_log(handle, ALPM_LOG_DEBUG,
00304             "setting install reason %u for %s\n", reason, pkg->name);
00305     if(alpm_pkg_get_reason(pkg) == reason) {
00306         /* we are done */
00307         return 0;
00308     }
00309     /* set reason (in pkgcache) */
00310     pkg->reason = reason;
00311     /* write DESC */
00312     if(_alpm_local_db_write(handle->db_local, pkg, INFRQ_DESC)) {
00313         RET_ERR(handle, ALPM_ERR_DB_WRITE, -1);
00314     }
00315 
00316     return 0;
00317 }
00318 
00319 /** @} */
00320 
00321 alpm_db_t *_alpm_db_new(const char *treename, int is_local)
00322 {
00323     alpm_db_t *db;
00324 
00325     CALLOC(db, 1, sizeof(alpm_db_t), return NULL);
00326     STRDUP(db->treename, treename, return NULL);
00327     if(is_local) {
00328         db->status |= DB_STATUS_LOCAL;
00329     } else {
00330         db->status &= ~DB_STATUS_LOCAL;
00331     }
00332 
00333     return db;
00334 }
00335 
00336 void _alpm_db_free(alpm_db_t *db)
00337 {
00338     /* cleanup pkgcache */
00339     _alpm_db_free_pkgcache(db);
00340     /* cleanup server list */
00341     FREELIST(db->servers);
00342     FREE(db->_path);
00343     FREE(db->treename);
00344     FREE(db);
00345 
00346     return;
00347 }
00348 
00349 const char *_alpm_db_path(alpm_db_t *db)
00350 {
00351     if(!db) {
00352         return NULL;
00353     }
00354     if(!db->_path) {
00355         const char *dbpath;
00356         size_t pathsize;
00357 
00358         dbpath = db->handle->dbpath;
00359         if(!dbpath) {
00360             _alpm_log(db->handle, ALPM_LOG_ERROR, _("database path is undefined\n"));
00361             RET_ERR(db->handle, ALPM_ERR_DB_OPEN, NULL);
00362         }
00363 
00364         if(db->status & DB_STATUS_LOCAL) {
00365             pathsize = strlen(dbpath) + strlen(db->treename) + 2;
00366             CALLOC(db->_path, 1, pathsize, RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL));
00367             sprintf(db->_path, "%s%s/", dbpath, db->treename);
00368         } else {
00369             pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 4;
00370             CALLOC(db->_path, 1, pathsize, RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL));
00371             /* all sync DBs now reside in the sync/ subdir of the dbpath */
00372             sprintf(db->_path, "%ssync/%s.db", dbpath, db->treename);
00373         }
00374         _alpm_log(db->handle, ALPM_LOG_DEBUG, "database path for tree %s set to %s\n",
00375                 db->treename, db->_path);
00376     }
00377     return db->_path;
00378 }
00379 
00380 int _alpm_db_cmp(const void *d1, const void *d2)
00381 {
00382     const alpm_db_t *db1 = d1;
00383     const alpm_db_t *db2 = d2;
00384     return strcmp(db1->treename, db2->treename);
00385 }
00386 
00387 alpm_list_t *_alpm_db_search(alpm_db_t *db, const alpm_list_t *needles)
00388 {
00389     const alpm_list_t *i, *j, *k;
00390     alpm_list_t *ret = NULL;
00391     /* copy the pkgcache- we will free the list var after each needle */
00392     alpm_list_t *list = alpm_list_copy(_alpm_db_get_pkgcache(db));
00393 
00394     for(i = needles; i; i = i->next) {
00395         char *targ;
00396         regex_t reg;
00397 
00398         if(i->data == NULL) {
00399             continue;
00400         }
00401         ret = NULL;
00402         targ = i->data;
00403         _alpm_log(db->handle, ALPM_LOG_DEBUG, "searching for target '%s'\n", targ);
00404 
00405         if(regcomp(&reg, targ, REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE) != 0) {
00406             RET_ERR(db->handle, ALPM_ERR_INVALID_REGEX, NULL);
00407         }
00408 
00409         for(j = list; j; j = j->next) {
00410             alpm_pkg_t *pkg = j->data;
00411             const char *matched = NULL;
00412             const char *name = pkg->name;
00413             const char *desc = alpm_pkg_get_desc(pkg);
00414 
00415             /* check name as regex AND as plain text */
00416             if(name && (regexec(&reg, name, 0, 0, 0) == 0 || strstr(name, targ))) {
00417                 matched = name;
00418             }
00419             /* check desc */
00420             else if(desc && regexec(&reg, desc, 0, 0, 0) == 0) {
00421                 matched = desc;
00422             }
00423             /* TODO: should we be doing this, and should we print something
00424              * differently when we do match it since it isn't currently printed? */
00425             if(!matched) {
00426                 /* check provides */
00427                 for(k = alpm_pkg_get_provides(pkg); k; k = k->next) {
00428                     alpm_depend_t *provide = k->data;
00429                     if(regexec(&reg, provide->name, 0, 0, 0) == 0) {
00430                         matched = provide->name;
00431                         break;
00432                     }
00433                 }
00434             }
00435             if(!matched) {
00436                 /* check groups */
00437                 for(k = alpm_pkg_get_groups(pkg); k; k = k->next) {
00438                     if(regexec(&reg, k->data, 0, 0, 0) == 0) {
00439                         matched = k->data;
00440                         break;
00441                     }
00442                 }
00443             }
00444 
00445             if(matched != NULL) {
00446                 _alpm_log(db->handle, ALPM_LOG_DEBUG,
00447                         "search target '%s' matched '%s'\n", targ, matched);
00448                 ret = alpm_list_add(ret, pkg);
00449             }
00450         }
00451 
00452         /* Free the existing search list, and use the returned list for the
00453          * next needle. This allows for AND-based package searching. */
00454         alpm_list_free(list);
00455         list = ret;
00456         regfree(&reg);
00457     }
00458 
00459     return ret;
00460 }
00461 
00462 /* Returns a new package cache from db.
00463  * It frees the cache if it already exists.
00464  */
00465 static int load_pkgcache(alpm_db_t *db)
00466 {
00467     _alpm_db_free_pkgcache(db);
00468 
00469     _alpm_log(db->handle, ALPM_LOG_DEBUG, "loading package cache for repository '%s'\n",
00470             db->treename);
00471     if(db->ops->populate(db) == -1) {
00472         _alpm_log(db->handle, ALPM_LOG_DEBUG,
00473                 "failed to load package cache for repository '%s'\n", db->treename);
00474         return -1;
00475     }
00476 
00477     db->status |= DB_STATUS_PKGCACHE;
00478     return 0;
00479 }
00480 
00481 static void free_groupcache(alpm_db_t *db)
00482 {
00483     alpm_list_t *lg;
00484 
00485     if(db == NULL || !(db->status & DB_STATUS_GRPCACHE)) {
00486         return;
00487     }
00488 
00489     _alpm_log(db->handle, ALPM_LOG_DEBUG,
00490             "freeing group cache for repository '%s'\n", db->treename);
00491 
00492     for(lg = db->grpcache; lg; lg = lg->next) {
00493         _alpm_group_free(lg->data);
00494         lg->data = NULL;
00495     }
00496     FREELIST(db->grpcache);
00497     db->status &= ~DB_STATUS_GRPCACHE;
00498 }
00499 
00500 void _alpm_db_free_pkgcache(alpm_db_t *db)
00501 {
00502     if(db == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
00503         return;
00504     }
00505 
00506     _alpm_log(db->handle, ALPM_LOG_DEBUG,
00507             "freeing package cache for repository '%s'\n", db->treename);
00508 
00509     if(db->pkgcache) {
00510         alpm_list_free_inner(db->pkgcache->list,
00511                 (alpm_list_fn_free)_alpm_pkg_free);
00512         _alpm_pkghash_free(db->pkgcache);
00513     }
00514     db->status &= ~DB_STATUS_PKGCACHE;
00515 
00516     free_groupcache(db);
00517 }
00518 
00519 alpm_pkghash_t *_alpm_db_get_pkgcache_hash(alpm_db_t *db)
00520 {
00521     if(db == NULL) {
00522         return NULL;
00523     }
00524 
00525     if(!(db->status & DB_STATUS_VALID)) {
00526         RET_ERR(db->handle, ALPM_ERR_DB_INVALID, NULL);
00527     }
00528 
00529     if(!(db->status & DB_STATUS_PKGCACHE)) {
00530         load_pkgcache(db);
00531     }
00532 
00533     return db->pkgcache;
00534 }
00535 
00536 alpm_list_t *_alpm_db_get_pkgcache(alpm_db_t *db)
00537 {
00538     alpm_pkghash_t *hash = _alpm_db_get_pkgcache_hash(db);
00539 
00540     if(hash == NULL) {
00541         return NULL;
00542     }
00543 
00544     return hash->list;
00545 }
00546 
00547 /* "duplicate" pkg then add it to pkgcache */
00548 int _alpm_db_add_pkgincache(alpm_db_t *db, alpm_pkg_t *pkg)
00549 {
00550     alpm_pkg_t *newpkg;
00551 
00552     if(db == NULL || pkg == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
00553         return -1;
00554     }
00555 
00556     if(_alpm_pkg_dup(pkg, &newpkg)) {
00557         return -1;
00558     }
00559 
00560     _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
00561                         newpkg->name, db->treename);
00562     db->pkgcache = _alpm_pkghash_add_sorted(db->pkgcache, newpkg);
00563 
00564     free_groupcache(db);
00565 
00566     return 0;
00567 }
00568 
00569 int _alpm_db_remove_pkgfromcache(alpm_db_t *db, alpm_pkg_t *pkg)
00570 {
00571     alpm_pkg_t *data = NULL;
00572 
00573     if(db == NULL || pkg == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
00574         return -1;
00575     }
00576 
00577     _alpm_log(db->handle, ALPM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
00578                         pkg->name, db->treename);
00579 
00580     db->pkgcache = _alpm_pkghash_remove(db->pkgcache, pkg, &data);
00581     if(data == NULL) {
00582         /* package not found */
00583         _alpm_log(db->handle, ALPM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
00584                             pkg->name, db->treename);
00585         return -1;
00586     }
00587 
00588     _alpm_pkg_free(data);
00589 
00590     free_groupcache(db);
00591 
00592     return 0;
00593 }
00594 
00595 alpm_pkg_t *_alpm_db_get_pkgfromcache(alpm_db_t *db, const char *target)
00596 {
00597     if(db == NULL) {
00598         return NULL;
00599     }
00600 
00601     alpm_pkghash_t *pkgcache = _alpm_db_get_pkgcache_hash(db);
00602     if(!pkgcache) {
00603         return NULL;
00604     }
00605 
00606     return _alpm_pkghash_find(pkgcache, target);
00607 }
00608 
00609 /* Returns a new group cache from db.
00610  */
00611 static int load_grpcache(alpm_db_t *db)
00612 {
00613     alpm_list_t *lp;
00614 
00615     if(db == NULL) {
00616         return -1;
00617     }
00618 
00619     _alpm_log(db->handle, ALPM_LOG_DEBUG, "loading group cache for repository '%s'\n",
00620             db->treename);
00621 
00622     for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
00623         const alpm_list_t *i;
00624         alpm_pkg_t *pkg = lp->data;
00625 
00626         for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
00627             const char *grpname = i->data;
00628             alpm_list_t *j;
00629             alpm_group_t *grp = NULL;
00630             int found = 0;
00631 
00632             /* first look through the group cache for a group with this name */
00633             for(j = db->grpcache; j; j = j->next) {
00634                 grp = j->data;
00635 
00636                 if(strcmp(grp->name, grpname) == 0
00637                         && !alpm_list_find_ptr(grp->packages, pkg)) {
00638                     grp->packages = alpm_list_add(grp->packages, pkg);
00639                     found = 1;
00640                     break;
00641                 }
00642             }
00643             if(found) {
00644                 continue;
00645             }
00646             /* we didn't find the group, so create a new one with this name */
00647             grp = _alpm_group_new(grpname);
00648             if(!grp) {
00649                 free_groupcache(db);
00650                 return -1;
00651             }
00652             grp->packages = alpm_list_add(grp->packages, pkg);
00653             db->grpcache = alpm_list_add(db->grpcache, grp);
00654         }
00655     }
00656 
00657     db->status |= DB_STATUS_GRPCACHE;
00658     return 0;
00659 }
00660 
00661 alpm_list_t *_alpm_db_get_groupcache(alpm_db_t *db)
00662 {
00663     if(db == NULL) {
00664         return NULL;
00665     }
00666 
00667     if(!(db->status & DB_STATUS_VALID)) {
00668         RET_ERR(db->handle, ALPM_ERR_DB_INVALID, NULL);
00669     }
00670 
00671     if(!(db->status & DB_STATUS_GRPCACHE)) {
00672         load_grpcache(db);
00673     }
00674 
00675     return db->grpcache;
00676 }
00677 
00678 alpm_group_t *_alpm_db_get_groupfromcache(alpm_db_t *db, const char *target)
00679 {
00680     alpm_list_t *i;
00681 
00682     if(db == NULL || target == NULL || strlen(target) == 0) {
00683         return NULL;
00684     }
00685 
00686     for(i = _alpm_db_get_groupcache(db); i; i = i->next) {
00687         alpm_group_t *info = i->data;
00688 
00689         if(strcmp(info->name, target) == 0) {
00690             return info;
00691         }
00692     }
00693 
00694     return NULL;
00695 }
00696 
00697 /* vim: set ts=2 sw=2 noet: */