summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2010-10-14 05:46:04 +0200
committerDan McGee <dan@archlinux.org>2010-10-14 05:46:04 +0200
commit68b50c81c79bcf01db0fd66ff523f32cc0dc67e9 (patch)
treee11e6be57e2ff49a67390e4659801190a0282375 /lib
parent6eedf06fcc224648155bc5253d6fe1975be8da00 (diff)
parent24d77291da93fcd5d09df2b1d1d05474616f18a5 (diff)
downloadpacman-68b50c81c79bcf01db0fd66ff523f32cc0dc67e9.tar.gz
pacman-68b50c81c79bcf01db0fd66ff523f32cc0dc67e9.tar.xz
Merge remote branch 'allan/backend'
Diffstat (limited to 'lib')
-rw-r--r--lib/libalpm/Makefile.am4
-rw-r--r--lib/libalpm/add.c7
-rw-r--r--lib/libalpm/be_local.c (renamed from lib/libalpm/be_files.c)707
-rw-r--r--lib/libalpm/be_package.c111
-rw-r--r--lib/libalpm/be_sync.c446
-rw-r--r--lib/libalpm/cache.c291
-rw-r--r--lib/libalpm/cache.h44
-rw-r--r--lib/libalpm/conflict.c1
-rw-r--r--lib/libalpm/db.c271
-rw-r--r--lib/libalpm/db.h48
-rw-r--r--lib/libalpm/deps.c1
-rw-r--r--lib/libalpm/package.c413
-rw-r--r--lib/libalpm/package.h63
-rw-r--r--lib/libalpm/po/POTFILES.in3
-rw-r--r--lib/libalpm/remove.c5
-rw-r--r--lib/libalpm/sync.c3
-rw-r--r--lib/libalpm/trans.c1
-rw-r--r--lib/libalpm/util.c45
-rw-r--r--lib/libalpm/util.h2
19 files changed, 1391 insertions, 1075 deletions
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am
index e136b548..bac30389 100644
--- a/lib/libalpm/Makefile.am
+++ b/lib/libalpm/Makefile.am
@@ -25,9 +25,9 @@ libalpm_la_SOURCES = \
alpm.h alpm.c \
alpm_list.h alpm_list.c \
backup.h backup.c \
- be_files.c \
+ be_local.c \
be_package.c \
- cache.h cache.c \
+ be_sync.c \
conflict.h conflict.c \
db.h db.c \
delta.h delta.c \
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index cc0c4c13..2b6b019b 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -40,7 +40,6 @@
#include "alpm_list.h"
#include "trans.h"
#include "util.h"
-#include "cache.h"
#include "log.h"
#include "backup.h"
#include "package.h"
@@ -498,7 +497,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
oldpkg = _alpm_pkg_dup(local);
/* make sure all infos are loaded because the database entry
* will be removed soon */
- _alpm_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
+ _alpm_local_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
EVENT(trans, PM_TRANS_EVT_UPGRADE_START, newpkg, oldpkg);
_alpm_log(PM_LOG_DEBUG, "upgrading package %s-%s\n",
@@ -544,7 +543,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
/* prepare directory for database entries so permission are correct after
changelog/install script installation (FS#12263) */
- if(_alpm_db_prepare(db, newpkg)) {
+ if(_alpm_local_db_prepare(db, newpkg)) {
alpm_logaction("error: could not create database entry %s-%s\n",
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
pm_errno = PM_ERR_DB_WRITE;
@@ -662,7 +661,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
- if(_alpm_db_write(db, newpkg, INFRQ_ALL)) {
+ if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
_alpm_log(PM_LOG_ERROR, _("could not update database entry %s-%s\n"),
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
alpm_logaction("error: could not update database entry %s-%s\n",
diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_local.c
index 0f055e03..cd6fac40 100644
--- a/lib/libalpm/be_files.c
+++ b/lib/libalpm/be_local.c
@@ -1,8 +1,8 @@
/*
- * be_files.c
+ * be_local.c
*
- * Copyright (c) 2006 by Christian Hamar <krics@linuxforum.hu>
- * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
+ * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2002-2006 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
@@ -40,329 +40,327 @@
/* libalpm */
#include "db.h"
#include "alpm_list.h"
-#include "cache.h"
#include "log.h"
#include "util.h"
#include "alpm.h"
#include "handle.h"
#include "package.h"
+#include "group.h"
#include "delta.h"
#include "deps.h"
#include "dload.h"
-static int checkdbdir(pmdb_t *db)
+#define LAZY_LOAD(info, errret) \
+ do { \
+ ALPM_LOG_FUNC; \
+ ASSERT(handle != NULL, return(errret)); \
+ ASSERT(pkg != NULL, return(errret)); \
+ if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & info)) { \
+ _alpm_local_db_read(pkg->origin_data.db, pkg, info); \
+ } \
+ } while(0)
+
+
+/* Cache-specific accessor functions. These implementations allow for lazy
+ * loading by the files backend when a data member is actually needed
+ * rather than loading all pieces of information when the package is first
+ * initialized.
+ */
+
+const char *_cache_get_filename(pmpkg_t *pkg)
{
- struct stat buf;
- const char *path = _alpm_db_path(db);
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->filename;
+}
- if(stat(path, &buf) != 0) {
- _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
- path);
- if(_alpm_makepath(path) != 0) {
- RET_ERR(PM_ERR_SYSTEM, -1);
- }
- } else if(!S_ISDIR(buf.st_mode)) {
- _alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path);
- if(unlink(path) != 0 || _alpm_makepath(path) != 0) {
- RET_ERR(PM_ERR_SYSTEM, -1);
- }
- }
- return(0);
+const char *_cache_get_name(pmpkg_t *pkg)
+{
+ ASSERT(pkg != NULL, return(NULL));
+ return pkg->name;
}
-/* create list of directories in db */
-static int dirlist_from_tar(const char *archive, alpm_list_t **dirlist)
+static const char *_cache_get_version(pmpkg_t *pkg)
{
- struct archive *_archive;
- struct archive_entry *entry;
+ ASSERT(pkg != NULL, return(NULL));
+ return pkg->version;
+}
- if((_archive = archive_read_new()) == NULL)
- RET_ERR(PM_ERR_LIBARCHIVE, -1);
+static const char *_cache_get_desc(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->desc;
+}
- archive_read_support_compression_all(_archive);
- archive_read_support_format_all(_archive);
+const char *_cache_get_url(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->url;
+}
- if(archive_read_open_filename(_archive, archive,
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive,
- archive_error_string(_archive));
- RET_ERR(PM_ERR_PKG_OPEN, -1);
- }
+time_t _cache_get_builddate(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, 0);
+ return pkg->builddate;
+}
- while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) {
- const struct stat *st;
- const char *entryname; /* the name of the file in the archive */
+time_t _cache_get_installdate(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, 0);
+ return pkg->installdate;
+}
- st = archive_entry_stat(entry);
- entryname = archive_entry_pathname(entry);
+const char *_cache_get_packager(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->packager;
+}
- if(S_ISDIR(st->st_mode)) {
- char *name = strdup(entryname);
- *dirlist = alpm_list_add(*dirlist, name);
- }
- }
- archive_read_finish(_archive);
+const char *_cache_get_md5sum(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->md5sum;
+}
- *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp);
- return(0);
+const char *_cache_get_arch(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->arch;
}
-static int is_dir(const char *path, struct dirent *entry)
+off_t _cache_get_size(pmpkg_t *pkg)
{
-#ifdef DT_DIR
- return(entry->d_type == DT_DIR);
-#else
- char buffer[PATH_MAX];
- snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->size;
+}
- struct stat sbuf;
- if (!stat(buffer, &sbuf)) {
- return(S_ISDIR(sbuf.st_mode));
- }
+off_t _cache_get_isize(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->isize;
+}
- return(0);
-#endif
+pmpkgreason_t _cache_get_reason(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->reason;
}
-/* create list of directories in db */
-static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist)
+alpm_list_t *_cache_get_licenses(pmpkg_t *pkg)
{
- DIR *dbdir;
- struct dirent *ent = NULL;
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->licenses;
+}
- dbdir = opendir(syncdbpath);
- if (dbdir != NULL) {
- while((ent = readdir(dbdir)) != NULL) {
- char *name = ent->d_name;
- size_t len;
- char *entry;
+alpm_list_t *_cache_get_groups(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->groups;
+}
- if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
- continue;
- }
+int _cache_has_force(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->force;
+}
- if(!is_dir(syncdbpath, ent)) {
- continue;
- }
+alpm_list_t *_cache_get_depends(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DEPENDS, NULL);
+ return pkg->depends;
+}
- len = strlen(name);
- MALLOC(entry, len + 2, RET_ERR(PM_ERR_MEMORY, -1));
- strcpy(entry, name);
- entry[len] = '/';
- entry[len+1] = '\0';
- *dirlist = alpm_list_add(*dirlist, entry);
- }
- closedir(dbdir);
- }
+alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DEPENDS, NULL);
+ return pkg->optdepends;
+}
- *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp);
- return(0);
+alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DEPENDS, NULL);
+ return pkg->conflicts;
}
-/* remove old directories from dbdir */
-static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist)
+alpm_list_t *_cache_get_provides(pmpkg_t *pkg)
{
- alpm_list_t *i;
- for (i = dirlist; i; i = i->next) {
- const char *name = i->data;
- char *dbdir;
- size_t len = strlen(syncdbpath) + strlen(name) + 2;
- MALLOC(dbdir, len, RET_ERR(PM_ERR_MEMORY, -1));
- snprintf(dbdir, len, "%s%s", syncdbpath, name);
- _alpm_log(PM_LOG_DEBUG, "removing: %s\n", dbdir);
- if(_alpm_rmrf(dbdir) != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not remove database directory %s\n"), dbdir);
- free(dbdir);
- RET_ERR(PM_ERR_DB_REMOVE, -1);
- }
- free(dbdir);
- }
- return(0);
+ LAZY_LOAD(INFRQ_DEPENDS, NULL);
+ return pkg->provides;
}
-/** Update a package database
- *
- * An update of the package database \a db will be attempted. Unless
- * \a force is true, the update will only be performed if the remote
- * database was modified since the last update.
- *
- * A transaction is necessary for this operation, in order to obtain a
- * database lock. During this transaction the front-end will be informed
- * of the download progress of the database via the download callback.
- *
- * Example:
- * @code
- * pmdb_t *db;
- * int result;
- * db = alpm_list_getdata(alpm_option_get_syncdbs());
- * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
- * result = alpm_db_update(0, db);
- * alpm_trans_release();
- *
- * if(result > 0) {
- * printf("Unable to update database: %s\n", alpm_strerrorlast());
- * } else if(result < 0) {
- * printf("Database already up to date\n");
- * } else {
- * printf("Database updated\n");
- * }
- * }
- * @endcode
- *
- * @ingroup alpm_databases
- * @note After a successful update, the \link alpm_db_get_pkgcache()
- * package cache \endlink will be invalidated
- * @param force if true, then forces the update, otherwise update only in case
- * the database isn't up to date
- * @param db pointer to the package database to update
- * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
- * to date
- */
-int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
+alpm_list_t *_cache_get_replaces(pmpkg_t *pkg)
{
- char *dbfile, *dbfilepath, *syncpath;
- const char *dbpath, *syncdbpath;
- alpm_list_t *newdirlist = NULL, *olddirlist = NULL;
- alpm_list_t *onlynew = NULL, *onlyold = NULL;
- size_t len;
- int ret;
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->replaces;
+}
+
+alpm_list_t *_cache_get_deltas(pmpkg_t *pkg)
+{
+ ASSERT(pkg != NULL, return(NULL));
+ /* local pkgs do not have deltas so nothing to load */
+ return pkg->deltas;
+}
+alpm_list_t *_cache_get_files(pmpkg_t *pkg)
+{
ALPM_LOG_FUNC;
/* Sanity checks */
- ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
- ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
- /* Verify we are in a transaction. This is done _mainly_ because we need a DB
- * lock - if we update without a db lock, we may kludge some other pacman
- * process that _has_ a lock.
- */
- ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
- ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
-
- if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
- RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
- }
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
- len = strlen(db->treename) + 4;
- MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
- sprintf(dbfile, "%s.db", db->treename);
-
- dbpath = alpm_option_get_dbpath();
- len = strlen(dbpath) + 6;
- MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1));
- sprintf(syncpath, "%s%s", dbpath, "sync/");
-
- ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
- free(dbfile);
- free(syncpath);
-
- if(ret == 1) {
- /* files match, do nothing */
- pm_errno = 0;
- return(1);
- } else if(ret == -1) {
- /* pm_errno was set by the download code */
- _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
- return(-1);
+ if(pkg->origin == PKG_FROM_LOCALDB
+ && !(pkg->infolevel & INFRQ_FILES)) {
+ _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
}
+ return pkg->files;
+}
- syncdbpath = _alpm_db_path(db);
-
- /* form the path to the db location */
- len = strlen(dbpath) + strlen(db->treename) + 9;
- MALLOC(dbfilepath, len, RET_ERR(PM_ERR_MEMORY, -1));
- sprintf(dbfilepath, "%ssync/%s.db", dbpath, db->treename);
-
- if(force) {
- /* if forcing update, remove the old dir and extract the db */
- if(_alpm_rmrf(syncdbpath) != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not remove database %s\n"), db->treename);
- RET_ERR(PM_ERR_DB_REMOVE, -1);
- } else {
- _alpm_log(PM_LOG_DEBUG, "database dir %s removed\n", _alpm_db_path(db));
- }
- } else {
- /* if not forcing, only remove and extract what is necessary */
- ret = dirlist_from_tar(dbfilepath, &newdirlist);
- if(ret) {
- goto cleanup;
- }
- ret = dirlist_from_fs(syncdbpath, &olddirlist);
- if(ret) {
- goto cleanup;
- }
+alpm_list_t *_cache_get_backup(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
- alpm_list_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew);
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
- ret = remove_olddir(syncdbpath, onlyold);
- if(ret) {
- goto cleanup;
- }
+ if(pkg->origin == PKG_FROM_LOCALDB
+ && !(pkg->infolevel & INFRQ_FILES)) {
+ _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
}
+ return pkg->backup;
+}
- /* Cache needs to be rebuilt */
- _alpm_db_free_pkgcache(db);
-
- checkdbdir(db);
- ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0);
-
-cleanup:
- FREELIST(newdirlist);
- FREELIST(olddirlist);
- alpm_list_free(onlynew);
- alpm_list_free(onlyold);
+/**
+ * Open a package changelog for reading. Similar to fopen in functionality,
+ * except that the returned 'file stream' is from the database.
+ * @param pkg the package (from db) to read the changelog
+ * @return a 'file stream' to the package changelog
+ */
+void *_cache_changelog_open(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
- free(dbfilepath);
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
+
+ char clfile[PATH_MAX];
+ snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
+ alpm_option_get_dbpath(),
+ alpm_db_get_name(alpm_pkg_get_db(pkg)),
+ alpm_pkg_get_name(pkg),
+ alpm_pkg_get_version(pkg));
+ return fopen(clfile, "r");
+}
- if(ret) {
- RET_ERR(PM_ERR_SYSTEM, -1);
- }
+/**
+ * Read data from an open changelog 'file stream'. Similar to fread in
+ * functionality, this function takes a buffer and amount of data to read.
+ * @param ptr a buffer to fill with raw changelog data
+ * @param size the size of the buffer
+ * @param pkg the package that the changelog is being read from
+ * @param fp a 'file stream' to the package changelog
+ * @return the number of characters read, or 0 if there is no more data
+ */
+size_t _cache_changelog_read(void *ptr, size_t size,
+ const pmpkg_t *pkg, const void *fp)
+{
+ return ( fread(ptr, 1, size, (FILE*)fp) );
+}
- return(0);
+/*
+int _cache_changelog_feof(const pmpkg_t *pkg, void *fp)
+{
+ return( feof((FILE*)fp) );
+}
+*/
+
+/**
+ * Close a package changelog for reading. Similar to fclose in functionality,
+ * except that the 'file stream' is from the database.
+ * @param pkg the package that the changelog was read from
+ * @param fp a 'file stream' to the package changelog
+ * @return whether closing the package changelog stream was successful
+ */
+int _cache_changelog_close(const pmpkg_t *pkg, void *fp)
+{
+ return( fclose((FILE*)fp) );
}
+/** The local database operations struct. Get package fields through
+ * lazy accessor methods that handle any backend loading and caching
+ * logic.
+ */
+static struct pkg_operations local_pkg_ops = {
+ .get_filename = _cache_get_filename,
+ .get_name = _cache_get_name,
+ .get_version = _cache_get_version,
+ .get_desc = _cache_get_desc,
+ .get_url = _cache_get_url,
+ .get_builddate = _cache_get_builddate,
+ .get_installdate = _cache_get_installdate,
+ .get_packager = _cache_get_packager,
+ .get_md5sum = _cache_get_md5sum,
+ .get_arch = _cache_get_arch,
+ .get_size = _cache_get_size,
+ .get_isize = _cache_get_isize,
+ .get_reason = _cache_get_reason,
+ .has_force = _cache_has_force,
+ .get_licenses = _cache_get_licenses,
+ .get_groups = _cache_get_groups,
+ .get_depends = _cache_get_depends,
+ .get_optdepends = _cache_get_optdepends,
+ .get_conflicts = _cache_get_conflicts,
+ .get_provides = _cache_get_provides,
+ .get_replaces = _cache_get_replaces,
+ .get_deltas = _cache_get_deltas,
+ .get_files = _cache_get_files,
+ .get_backup = _cache_get_backup,
+
+ .changelog_open = _cache_changelog_open,
+ .changelog_read = _cache_changelog_read,
+ .changelog_close = _cache_changelog_close,
+};
-static int splitname(const char *target, pmpkg_t *pkg)
+static int checkdbdir(pmdb_t *db)
{
- /* the format of a db entry is as follows:
- * package-version-rel/
- * package name can contain hyphens, so parse from the back- go back
- * two hyphens and we have split the version from the name.
- */
- char *tmp, *p, *q;
+ struct stat buf;
+ const char *path = _alpm_db_path(db);
- if(target == NULL || pkg == NULL) {
- return(-1);
- }
- STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1));
- p = tmp + strlen(tmp);
-
- /* do the magic parsing- find the beginning of the version string
- * by doing two iterations of same loop to lop off two hyphens */
- for(q = --p; *q && *q != '-'; q--);
- for(p = --q; *p && *p != '-'; p--);
- if(*p != '-' || p == tmp) {
- return(-1);
+ if(stat(path, &buf) != 0) {
+ _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
+ path);
+ if(_alpm_makepath(path) != 0) {
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
+ } else if(!S_ISDIR(buf.st_mode)) {
+ _alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path);
+ if(unlink(path) != 0 || _alpm_makepath(path) != 0) {
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
}
+ return(0);
+}
- /* copy into fields and return */
- if(pkg->version) {
- FREE(pkg->version);
- }
- STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1));
- /* insert a terminator at the end of the name (on hyphen)- then copy it */
- *p = '\0';
- if(pkg->name) {
- FREE(pkg->name);
+static int is_dir(const char *path, struct dirent *entry)
+{
+#ifdef DT_DIR
+ return(entry->d_type == DT_DIR);
+#else
+ char buffer[PATH_MAX];
+ snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+ struct stat sbuf;
+ if (!stat(buffer, &sbuf)) {
+ return(S_ISDIR(sbuf.st_mode));
}
- STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1));
- free(tmp);
return(0);
+#endif
}
-int _alpm_db_populate(pmdb_t *db)
+int _alpm_local_db_populate(pmdb_t *db)
{
int count = 0;
struct dirent *ent = NULL;
@@ -380,6 +378,7 @@ int _alpm_db_populate(pmdb_t *db)
}
while((ent = readdir(dbdir)) != NULL) {
const char *name = ent->d_name;
+
pmpkg_t *pkg;
if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
@@ -395,7 +394,7 @@ int _alpm_db_populate(pmdb_t *db)
return(-1);
}
/* split the db entry name */
- if(splitname(name, pkg) != 0) {
+ if(_alpm_splitname(name, pkg) != 0) {
_alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
name);
_alpm_pkg_free(pkg);
@@ -410,12 +409,15 @@ int _alpm_db_populate(pmdb_t *db)
}
/* explicitly read with only 'BASE' data, accessors will handle the rest */
- if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) {
+ if(_alpm_local_db_read(db, pkg, INFRQ_BASE) == -1) {
_alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);
_alpm_pkg_free(pkg);
continue;
}
- pkg->origin = PKG_FROM_CACHE;
+
+ pkg->origin = PKG_FROM_LOCALDB;
+ pkg->ops = &local_pkg_ops;
+
pkg->origin_data.db = db;
/* add to the collection */
_alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
@@ -443,7 +445,8 @@ static char *get_pkgpath(pmdb_t *db, pmpkg_t *info)
return(pkgpath);
}
-int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
+
+int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
{
FILE *fp = NULL;
char path[PATH_MAX];
@@ -457,7 +460,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
}
if(info == NULL || info->name == NULL || info->version == NULL) {
- _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n");
+ _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_local_db_read, skipping\n");
return(-1);
}
@@ -518,11 +521,6 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
"mismatch on package %s\n"), db->treename, info->name);
}
- } else if(strcmp(line, "%FILENAME%") == 0) {
- if(fgets(line, sizeof(line), fp) == NULL) {
- goto error;
- }
- STRDUP(info->filename, _alpm_strtrim(line), goto error);
} else if(strcmp(line, "%DESC%") == 0) {
if(fgets(line, sizeof(line), fp) == NULL) {
goto error;
@@ -592,7 +590,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
goto error;
}
info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line));
- } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) {
+ } else if(strcmp(line, "%SIZE%") == 0) {
/* NOTE: the CSIZE and SIZE fields both share the "size" field
* in the pkginfo_t struct. This can be done b/c CSIZE
* is currently only used in sync databases, and SIZE is
@@ -602,24 +600,8 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
goto error;
}
info->size = atol(_alpm_strtrim(line));
- /* also store this value to isize if isize is unset */
- if(info->isize == 0) {
- info->isize = info->size;
- }
- } else if(strcmp(line, "%ISIZE%") == 0) {
- /* ISIZE (installed size) tag only appears in sync repositories,
- * not the local one. */
- if(fgets(line, sizeof(line), fp) == NULL) {
- goto error;
- }
- info->isize = atol(_alpm_strtrim(line));
- } else if(strcmp(line, "%MD5SUM%") == 0) {
- /* MD5SUM tag only appears in sync repositories,
- * not the local one. */
- if(fgets(line, sizeof(line), fp) == NULL) {
- goto error;
- }
- STRDUP(info->md5sum, _alpm_strtrim(line), goto error);
+ /* also store this value to isize */
+ info->isize = info->size;
} else if(strcmp(line, "%REPLACES%") == 0) {
while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
char *linedup;
@@ -702,29 +684,6 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
fp = NULL;
}
- /* DELTAS */
- if(inforeq & INFRQ_DELTAS) {
- snprintf(path, PATH_MAX, "%sdeltas", pkgpath);
- if((fp = fopen(path, "r"))) {
- while(!feof(fp)) {
- if(fgets(line, sizeof(line), fp) == NULL) {
- break;
- }
- _alpm_strtrim(line);
- if(strcmp(line, "%DELTAS%") == 0) {
- while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
- pmdelta_t *delta = _alpm_delta_parse(line);
- if(delta) {
- info->deltas = alpm_list_add(info->deltas, delta);
- }
- }
- }
- }
- fclose(fp);
- fp = NULL;
- }
- }
-
/* INSTALL */
if(inforeq & INFRQ_SCRIPTLET) {
snprintf(path, PATH_MAX, "%sinstall", pkgpath);
@@ -747,7 +706,7 @@ error:
return(-1);
}
-int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info)
+int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info)
{
mode_t oldmask;
int retval = 0;
@@ -771,14 +730,13 @@ int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info)
return(retval);
}
-int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
+int _alpm_local_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
{
FILE *fp = NULL;
char path[PATH_MAX];
mode_t oldmask;
alpm_list_t *lp = NULL;
int retval = 0;
- int local = 0;
char *pkgpath = NULL;
ALPM_LOG_FUNC;
@@ -792,8 +750,8 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
/* make sure we have a sane umask */
oldmask = umask(0022);
- if(strcmp(db->treename, "local") == 0) {
- local = 1;
+ if(strcmp(db->treename, "local") != 0) {
+ return(-1);
}
/* DESC */
@@ -829,63 +787,49 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
if(info->force) {
fprintf(fp, "%%FORCE%%\n\n");
}
- if(local) {
- if(info->url) {
- fprintf(fp, "%%URL%%\n"
- "%s\n\n", info->url);
- }
- if(info->licenses) {
- fputs("%LICENSE%\n", fp);
- for(lp = info->licenses; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->arch) {
- fprintf(fp, "%%ARCH%%\n"
- "%s\n\n", info->arch);
- }
- if(info->builddate) {
- fprintf(fp, "%%BUILDDATE%%\n"
- "%ld\n\n", info->builddate);
- }
- if(info->installdate) {
- fprintf(fp, "%%INSTALLDATE%%\n"
- "%ld\n\n", info->installdate);
- }
- if(info->packager) {
- fprintf(fp, "%%PACKAGER%%\n"
- "%s\n\n", info->packager);
- }
- if(info->isize) {
- /* only write installed size, csize is irrelevant once installed */
- fprintf(fp, "%%SIZE%%\n"
- "%jd\n\n", (intmax_t)info->isize);
- }
- if(info->reason) {
- fprintf(fp, "%%REASON%%\n"
- "%u\n\n", info->reason);
- }
- } else {
- if(info->size) {
- fprintf(fp, "%%CSIZE%%\n"
- "%jd\n\n", (intmax_t)info->size);
- }
- if(info->isize) {
- fprintf(fp, "%%ISIZE%%\n"
- "%jd\n\n", (intmax_t)info->isize);
- }
- if(info->md5sum) {
- fprintf(fp, "%%MD5SUM%%\n"
- "%s\n\n", info->md5sum);
+ if(info->url) {
+ fprintf(fp, "%%URL%%\n"
+ "%s\n\n", info->url);
+ }
+ if(info->licenses) {
+ fputs("%LICENSE%\n", fp);
+ for(lp = info->licenses; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
}
+ fprintf(fp, "\n");
+ }
+ if(info->arch) {
+ fprintf(fp, "%%ARCH%%\n"
+ "%s\n\n", info->arch);
+ }
+ if(info->builddate) {
+ fprintf(fp, "%%BUILDDATE%%\n"
+ "%ld\n\n", info->builddate);
+ }
+ if(info->installdate) {
+ fprintf(fp, "%%INSTALLDATE%%\n"
+ "%ld\n\n", info->installdate);
}
+ if(info->packager) {
+ fprintf(fp, "%%PACKAGER%%\n"
+ "%s\n\n", info->packager);
+ }
+ if(info->isize) {
+ /* only write installed size, csize is irrelevant once installed */
+ fprintf(fp, "%%SIZE%%\n"
+ "%jd\n\n", (intmax_t)info->isize);
+ }
+ if(info->reason) {
+ fprintf(fp, "%%REASON%%\n"
+ "%u\n\n", info->reason);
+ }
+
fclose(fp);
fp = NULL;
}
/* FILES */
- if(local && (inforeq & INFRQ_FILES)) {
+ if(inforeq & INFRQ_FILES) {
_alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n",
info->name, info->version);
snprintf(path, PATH_MAX, "%sfiles", pkgpath);
@@ -970,7 +914,7 @@ cleanup:
return(retval);
}
-int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
+int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info)
{
int ret = 0;
char *pkgpath = NULL;
@@ -991,4 +935,33 @@ int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
return(ret);
}
+struct db_operations local_db_ops = {
+ .populate = _alpm_local_db_populate,
+ .unregister = _alpm_db_unregister,
+};
+
+pmdb_t *_alpm_db_register_local(void)
+{
+ pmdb_t *db;
+
+ ALPM_LOG_FUNC;
+
+ if(handle->db_local != NULL) {
+ _alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n"));
+ RET_ERR(PM_ERR_DB_NOT_NULL, NULL);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "registering local database\n");
+
+ db = _alpm_db_new("local", 1);
+ db->ops = &local_db_ops;
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_CREATE, NULL);
+ }
+
+ handle->db_local = db;
+ return(db);
+}
+
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
index 3d8c4e38..4a8624e5 100644
--- a/lib/libalpm/be_package.c
+++ b/lib/libalpm/be_package.c
@@ -26,6 +26,7 @@
#include <limits.h>
#include <ctype.h>
#include <locale.h> /* setlocale */
+#include <errno.h>
/* libarchive */
#include <archive.h>
@@ -39,6 +40,114 @@
#include "deps.h" /* _alpm_splitdep */
/**
+ * Open a package changelog for reading. Similar to fopen in functionality,
+ * except that the returned 'file stream' is from an archive.
+ * @param pkg the package (file) to read the changelog
+ * @return a 'file stream' to the package changelog
+ */
+void *_package_changelog_open(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ ASSERT(pkg != NULL, return(NULL));
+
+ struct archive *archive = NULL;
+ struct archive_entry *entry;
+ const char *pkgfile = pkg->origin_data.file;
+ int ret = ARCHIVE_OK;
+
+ if((archive = archive_read_new()) == NULL) {
+ RET_ERR(PM_ERR_LIBARCHIVE, NULL);
+ }
+
+ archive_read_support_compression_all(archive);
+ archive_read_support_format_all(archive);
+
+ if (archive_read_open_filename(archive, pkgfile,
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ RET_ERR(PM_ERR_PKG_OPEN, NULL);
+ }
+
+ while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
+ const char *entry_name = archive_entry_pathname(entry);
+
+ if(strcmp(entry_name, ".CHANGELOG") == 0) {
+ return(archive);
+ }
+ }
+ /* we didn't find a changelog */
+ archive_read_finish(archive);
+ errno = ENOENT;
+
+ return(NULL);
+}
+
+/**
+ * Read data from an open changelog 'file stream'. Similar to fread in
+ * functionality, this function takes a buffer and amount of data to read.
+ * @param ptr a buffer to fill with raw changelog data
+ * @param size the size of the buffer
+ * @param pkg the package that the changelog is being read from
+ * @param fp a 'file stream' to the package changelog
+ * @return the number of characters read, or 0 if there is no more data
+ */
+size_t _package_changelog_read(void *ptr, size_t size,
+ const pmpkg_t *pkg, const void *fp)
+{
+ ssize_t sret = archive_read_data((struct archive*)fp, ptr, size);
+ /* Report error (negative values) */
+ if(sret < 0) {
+ pm_errno = PM_ERR_LIBARCHIVE;
+ return(0);
+ } else {
+ return((size_t)sret);
+ }
+}
+
+/*
+int _package_changelog_feof(const pmpkg_t *pkg, void *fp)
+{
+ // note: this doesn't quite work, no feof in libarchive
+ return( archive_read_data((struct archive*)fp, NULL, 0) );
+}
+*/
+
+/**
+ * Close a package changelog for reading. Similar to fclose in functionality,
+ * except that the 'file stream' is from an archive.
+ * @param pkg the package (file) that the changelog was read from
+ * @param fp a 'file stream' to the package changelog
+ * @return whether closing the package changelog stream was successful
+ */
+int _package_changelog_close(const pmpkg_t *pkg, void *fp)
+{
+ return( archive_read_finish((struct archive *)fp) );
+}
+
+
+/** Package file operations struct accessor. We implement this as a method
+ * rather than a static struct as in be_files because we want to reuse the
+ * majority of the default_pkg_ops struct and add only a few operations of
+ * our own on top. The static file_pkg_ops variable inside this function
+ * lets us only initialize an operations struct once which can always be
+ * accessed by this method.
+ */
+static struct pkg_operations *get_file_pkg_ops()
+{
+ static struct pkg_operations *file_pkg_ops = NULL;
+ /* determine whether our static file_pkg_ops struct has been initialized */
+ if(!file_pkg_ops) {
+ MALLOC(file_pkg_ops, sizeof(struct pkg_operations),
+ RET_ERR(PM_ERR_MEMORY, NULL));
+ memcpy(file_pkg_ops, &default_pkg_ops, sizeof(struct pkg_operations));
+ file_pkg_ops->changelog_open = _package_changelog_open;
+ file_pkg_ops->changelog_read = _package_changelog_read;
+ file_pkg_ops->changelog_close = _package_changelog_close;
+ }
+ return(file_pkg_ops);
+}
+
+/**
* Parses the package description file for a package into a pmpkg_t struct.
* @param archive the archive to read from, pointed at the .PKGINFO entry
* @param newpkg an empty pmpkg_t struct to fill with package info
@@ -234,7 +343,9 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)
/* internal fields for package struct */
newpkg->origin = PKG_FROM_FILE;
+ /* TODO eventually kill/move this? */
newpkg->origin_data.file = strdup(pkgfile);
+ newpkg->ops = get_file_pkg_ops();
if(full) {
/* "checking for conflicts" requires a sorted list, ensure that here */
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
new file mode 100644
index 00000000..78038576
--- /dev/null
+++ b/lib/libalpm/be_sync.c
@@ -0,0 +1,446 @@
+/*
+ * be_sync.c
+ *
+ * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <locale.h>
+
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
+/* libalpm */
+#include "util.h"
+#include "log.h"
+#include "alpm.h"
+#include "alpm_list.h"
+#include "package.h"
+#include "handle.h"
+#include "delta.h"
+#include "deps.h"
+#include "dload.h"
+
+/** Update a package database
+ *
+ * An update of the package database \a db will be attempted. Unless
+ * \a force is true, the update will only be performed if the remote
+ * database was modified since the last update.
+ *
+ * A transaction is necessary for this operation, in order to obtain a
+ * database lock. During this transaction the front-end will be informed
+ * of the download progress of the database via the download callback.
+ *
+ * Example:
+ * @code
+ * pmdb_t *db;
+ * int result;
+ * db = alpm_list_getdata(alpm_option_get_syncdbs());
+ * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
+ * result = alpm_db_update(0, db);
+ * alpm_trans_release();
+ *
+ * if(result > 0) {
+ * printf("Unable to update database: %s\n", alpm_strerrorlast());
+ * } else if(result < 0) {
+ * printf("Database already up to date\n");
+ * } else {
+ * printf("Database updated\n");
+ * }
+ * }
+ * @endcode
+ *
+ * @ingroup alpm_databases
+ * @note After a successful update, the \link alpm_db_get_pkgcache()
+ * package cache \endlink will be invalidated
+ * @param force if true, then forces the update, otherwise update only in case
+ * the database isn't up to date
+ * @param db pointer to the package database to update
+ * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
+ * to date
+ */
+int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
+{
+ char *dbfile, *syncpath;
+ const char *dbpath;
+ size_t len;
+ int ret;
+
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
+ ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ /* Verify we are in a transaction. This is done _mainly_ because we need a DB
+ * lock - if we update without a db lock, we may kludge some other pacman
+ * process that _has_ a lock.
+ */
+ ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
+ ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
+
+ if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
+ RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+ }
+
+ len = strlen(db->treename) + 4;
+ MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
+ sprintf(dbfile, "%s.db", db->treename);
+
+ dbpath = alpm_option_get_dbpath();
+ len = strlen(dbpath) + 6;
+ MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1));
+ sprintf(syncpath, "%s%s", dbpath, "sync/");
+
+ ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
+ free(dbfile);
+ free(syncpath);
+
+ if(ret == 1) {
+ /* files match, do nothing */
+ pm_errno = 0;
+ return(1);
+ } else if(ret == -1) {
+ /* pm_errno was set by the download code */
+ _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
+ return(-1);
+ }
+
+ /* Cache needs to be rebuilt */
+ _alpm_db_free_pkgcache(db);
+
+ return(0);
+}
+
+int _alpm_sync_db_populate(pmdb_t *db)
+{
+ int count = 0;
+ struct archive *archive;
+ struct archive_entry *entry;
+ const char * archive_path;
+
+ ALPM_LOG_FUNC;
+
+ ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
+
+ if((archive = archive_read_new()) == NULL)
+ RET_ERR(PM_ERR_LIBARCHIVE, 1);
+
+ archive_read_support_compression_all(archive);
+ archive_read_support_format_all(archive);
+
+ if(archive_read_open_filename(archive, _alpm_db_path(db),
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), _alpm_db_path(db),
+ archive_error_string(archive));
+ RET_ERR(PM_ERR_PKG_OPEN, 1);
+ }
+
+ while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
+ const struct stat *st;
+ const char *name;
+ pmpkg_t *pkg;
+
+ st = archive_entry_stat(entry);
+
+ if(S_ISDIR(st->st_mode)) {
+ archive_path = archive_entry_pathname(entry);
+
+ pkg = _alpm_pkg_new();
+ if(pkg == NULL) {
+ archive_read_finish(archive);
+ return(-1);
+ }
+
+ name = archive_entry_pathname(entry);
+
+ if(_alpm_splitname(name, pkg) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
+ name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ /* duplicated database entries are not allowed */
+ if(_alpm_pkg_find(db->pkgcache, pkg->name)) {
+ _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ pkg->origin = PKG_FROM_SYNCDB;
+ pkg->ops = &default_pkg_ops;
+ pkg->origin_data.db = db;
+
+ /* add to the collection */
+ _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
+ pkg->name, db->treename);
+ db->pkgcache = alpm_list_add(db->pkgcache, pkg);
+ count++;
+ } else {
+ /* we have desc, depends or deltas - parse it */
+ _alpm_sync_db_read(db, archive, entry);
+ }
+ }
+
+ db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp);
+ archive_read_finish(archive);
+
+ return(count);
+}
+
+int _alpm_sync_db_read(pmdb_t *db, struct archive *archive, struct archive_entry *entry)
+{
+ char line[1024];
+ const char *entryname;
+ char *filename, *pkgname, *p, *q;
+ pmpkg_t *pkg;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_NULL, -1);
+ }
+
+ if(entry == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
+ return(-1);
+ }
+
+ entryname = archive_entry_pathname(entry);
+
+ _alpm_log(PM_LOG_FUNCTION, "loading package data from archive entry %s\n",
+ entryname);
+
+ /* get package and db file names */
+ STRDUP(pkgname, entryname, RET_ERR(PM_ERR_MEMORY, -1));
+ p = pkgname + strlen(pkgname);
+ for(q = --p; *q && *q != '/'; q--);
+ STRDUP(filename, q+1, RET_ERR(PM_ERR_MEMORY, -1));
+ for(p = --q; *p && *p != '-'; p--);
+ for(q = --p; *q && *q != '-'; q--);
+ *q = '\0';
+
+ /* package is already in db due to parsing of directory name */
+ pkg = _alpm_pkg_find(db->pkgcache, pkgname);
+ if(pkg == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "package %s not found in %s sync database",
+ pkgname, db->treename);
+ return(-1);
+ }
+
+ if(strcmp(filename, "desc") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) {
+ _alpm_strtrim(line);
+ if(strcmp(line, "%NAME%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ if(strcmp(_alpm_strtrim(line), pkg->name) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
+ "mismatch on package %s\n"), db->treename, pkg->name);
+ }
+ } else if(strcmp(line, "%VERSION%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ if(strcmp(_alpm_strtrim(line), pkg->version) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
+ "mismatch on package %s\n"), db->treename, pkg->name);
+ }
+ } else if(strcmp(line, "%FILENAME%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ STRDUP(pkg->filename, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%DESC%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ STRDUP(pkg->desc, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%GROUPS%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ pkg->groups = alpm_list_add(pkg->groups, linedup);
+ }
+ } else if(strcmp(line, "%URL%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ STRDUP(pkg->url, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%LICENSE%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) &&
+ strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ pkg->licenses = alpm_list_add(pkg->licenses, linedup);
+ }
+ } else if(strcmp(line, "%ARCH%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ STRDUP(pkg->arch, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%BUILDDATE%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ _alpm_strtrim(line);
+
+ char first = tolower((unsigned char)line[0]);
+ if(first > 'a' && first < 'z') {
+ struct tm tmp_tm = {0}; /* initialize to null in case of failure */
+ setlocale(LC_TIME, "C");
+ strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+ pkg->builddate = mktime(&tmp_tm);
+ setlocale(LC_TIME, "");
+ } else {
+ pkg->builddate = atol(line);
+ }
+ } else if(strcmp(line, "%PACKAGER%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ STRDUP(pkg->packager, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%CSIZE%") == 0) {
+ /* NOTE: the CSIZE and SIZE fields both share the "size" field
+ * in the pkginfo_t struct. This can be done b/c CSIZE
+ * is currently only used in sync databases, and SIZE is
+ * only used in local databases.
+ */
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ pkg->size = atol(_alpm_strtrim(line));
+ /* also store this value to isize if isize is unset */
+ if(pkg->isize == 0) {
+ pkg->isize = pkg->size;
+ }
+ } else if(strcmp(line, "%ISIZE%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ pkg->isize = atol(_alpm_strtrim(line));
+ } else if(strcmp(line, "%MD5SUM%") == 0) {
+ if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) {
+ goto error;
+ }
+ STRDUP(pkg->md5sum, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%REPLACES%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) &&
+ strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ pkg->replaces = alpm_list_add(pkg->replaces, linedup);
+ }
+ } else if(strcmp(line, "%FORCE%") == 0) {
+ pkg->force = 1;
+ }
+ }
+ } else if(strcmp(filename, "depends") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) {
+ _alpm_strtrim(line);
+ if(strcmp(line, "%DEPENDS%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) &&
+ strlen(_alpm_strtrim(line))) {
+ pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line));
+ pkg->depends = alpm_list_add(pkg->depends, dep);
+ }
+ } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) &&
+ strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ pkg->optdepends = alpm_list_add(pkg->optdepends, linedup);
+ }
+ } else if(strcmp(line, "%CONFLICTS%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) &&
+ strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ pkg->conflicts = alpm_list_add(pkg->conflicts, linedup);
+ }
+ } else if(strcmp(line, "%PROVIDES%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) &&
+ strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ pkg->provides = alpm_list_add(pkg->provides, linedup);
+ }
+ }
+ }
+ } else if(strcmp(filename, "deltas") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) {
+ _alpm_strtrim(line);
+ if(strcmp(line, "%DELTAS%") == 0) {
+ while(_alpm_archive_fgets(line, sizeof(line), archive) && strlen(_alpm_strtrim(line))) {
+ pmdelta_t *delta = _alpm_delta_parse(line);
+ if(delta) {
+ pkg->deltas = alpm_list_add(pkg->deltas, delta);
+ }
+ }
+ }
+ }
+ } else {
+ /* unknown database file */
+ _alpm_log(PM_LOG_DEBUG, "unknown database file: %s", filename);
+ }
+
+error:
+ FREE(pkgname);
+ FREE(filename);
+ return(0);
+}
+
+struct db_operations sync_db_ops = {
+ .populate = _alpm_sync_db_populate,
+ .unregister = _alpm_db_unregister,
+};
+
+pmdb_t *_alpm_db_register_sync(const char *treename)
+{
+ pmdb_t *db;
+ alpm_list_t *i;
+
+ ALPM_LOG_FUNC;
+
+ for(i = handle->dbs_sync; i; i = i->next) {
+ pmdb_t *sdb = i->data;
+ if(strcmp(treename, sdb->treename) == 0) {
+ _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
+ return sdb;
+ }
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
+
+ db = _alpm_db_new(treename, 0);
+ db->ops = &sync_db_ops;
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_CREATE, NULL);
+ }
+
+ handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
+ return(db);
+}
+
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/cache.c b/lib/libalpm/cache.c
deleted file mode 100644
index a9a7edd9..00000000
--- a/lib/libalpm/cache.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * cache.c
- *
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
- * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-/* libalpm */
-#include "cache.h"
-#include "alpm_list.h"
-#include "log.h"
-#include "alpm.h"
-#include "util.h"
-#include "package.h"
-#include "group.h"
-#include "db.h"
-
-/* Returns a new package cache from db.
- * It frees the cache if it already exists.
- */
-int _alpm_db_load_pkgcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(-1);
- }
- _alpm_db_free_pkgcache(db);
-
- _alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n",
- db->treename);
- if(_alpm_db_populate(db) == -1) {
- _alpm_log(PM_LOG_DEBUG,
- "failed to load package cache for repository '%s'\n", db->treename);
- return(-1);
- }
-
- db->pkgcache_loaded = 1;
- return(0);
-}
-
-void _alpm_db_free_pkgcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->pkgcache_loaded) {
- return;
- }
-
- _alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n",
- db->treename);
-
- alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free);
- alpm_list_free(db->pkgcache);
- db->pkgcache = NULL;
- db->pkgcache_loaded = 0;
-
- _alpm_db_free_grpcache(db);
-}
-
-alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(NULL);
- }
-
- if(!db->pkgcache_loaded) {
- _alpm_db_load_pkgcache(db);
- }
-
- /* hmmm, still NULL ?*/
- if(!db->pkgcache) {
- _alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename);
- }
-
- return(db->pkgcache);
-}
-
-/* "duplicate" pkg with BASE info (to spare some memory) then add it to pkgcache */
-int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)
-{
- pmpkg_t *newpkg;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
- return(-1);
- }
-
- newpkg = _alpm_pkg_new();
- if(newpkg == NULL) {
- return(-1);
- }
- newpkg->name = strdup(pkg->name);
- newpkg->version = strdup(pkg->version);
- if(newpkg->name == NULL || newpkg->version == NULL) {
- pm_errno = PM_ERR_MEMORY;
- _alpm_pkg_free(newpkg);
- return(-1);
- }
- newpkg->origin = PKG_FROM_CACHE;
- newpkg->origin_data.db = db;
- newpkg->infolevel = INFRQ_BASE;
-
- _alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
- alpm_pkg_get_name(newpkg), db->treename);
- db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp);
-
- _alpm_db_free_grpcache(db);
-
- return(0);
-}
-
-int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg)
-{
- void *vdata;
- pmpkg_t *data;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
- return(-1);
- }
-
- _alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
- alpm_pkg_get_name(pkg), db->treename);
-
- db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata);
- data = vdata;
- if(data == NULL) {
- /* package not found */
- _alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
- alpm_pkg_get_name(pkg), db->treename);
- return(-1);
- }
-
- _alpm_pkg_free(data);
-
- _alpm_db_free_grpcache(db);
-
- return(0);
-}
-
-pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(NULL);
- }
-
- alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db);
- if(!pkgcache) {
- _alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n",
- target);
- return(NULL);
- }
-
- return(_alpm_pkg_find(pkgcache, target));
-}
-
-/* Returns a new group cache from db.
- */
-int _alpm_db_load_grpcache(pmdb_t *db)
-{
- alpm_list_t *lp;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(-1);
- }
-
- _alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n",
- db->treename);
-
- for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
- const alpm_list_t *i;
- pmpkg_t *pkg = lp->data;
-
- for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
- const char *grpname = i->data;
- alpm_list_t *j;
- pmgrp_t *grp = NULL;
- int found = 0;
-
- /* first look through the group cache for a group with this name */
- for(j = db->grpcache; j; j = j->next) {
- grp = j->data;
-
- if(strcmp(grp->name, grpname) == 0
- && !alpm_list_find_ptr(grp->packages, pkg)) {
- grp->packages = alpm_list_add(grp->packages, pkg);
- found = 1;
- break;
- }
- }
- if(found) {
- continue;
- }
- /* we didn't find the group, so create a new one with this name */
- grp = _alpm_grp_new(grpname);
- grp->packages = alpm_list_add(grp->packages, pkg);
- db->grpcache = alpm_list_add(db->grpcache, grp);
- }
- }
-
- db->grpcache_loaded = 1;
- return(0);
-}
-
-void _alpm_db_free_grpcache(pmdb_t *db)
-{
- alpm_list_t *lg;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->grpcache_loaded) {
- return;
- }
-
- _alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n",
- db->treename);
-
- for(lg = db->grpcache; lg; lg = lg->next) {
- _alpm_grp_free(lg->data);
- lg->data = NULL;
- }
- FREELIST(db->grpcache);
- db->grpcache_loaded = 0;
-}
-
-alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(NULL);
- }
-
- if(!db->grpcache_loaded) {
- _alpm_db_load_grpcache(db);
- }
-
- return(db->grpcache);
-}
-
-pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target)
-{
- alpm_list_t *i;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || target == NULL || strlen(target) == 0) {
- return(NULL);
- }
-
- for(i = _alpm_db_get_grpcache(db); i; i = i->next) {
- pmgrp_t *info = i->data;
-
- if(strcmp(info->name, target) == 0) {
- return(info);
- }
- }
-
- return(NULL);
-}
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/cache.h b/lib/libalpm/cache.h
deleted file mode 100644
index 6ddcd186..00000000
--- a/lib/libalpm/cache.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * cache.h
- *
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
- * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef _ALPM_CACHE_H
-#define _ALPM_CACHE_H
-
-#include "db.h"
-#include "alpm_list.h"
-#include "group.h"
-#include "package.h"
-
-/* packages */
-int _alpm_db_load_pkgcache(pmdb_t *db);
-void _alpm_db_free_pkgcache(pmdb_t *db);
-int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg);
-int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg);
-alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db);
-int _alpm_db_ensure_pkgcache(pmdb_t *db, pmdbinfrq_t infolevel);
-pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target);
-/* groups */
-int _alpm_db_load_grpcache(pmdb_t *db);
-void _alpm_db_free_grpcache(pmdb_t *db);
-alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db);
-pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target);
-
-#endif /* _ALPM_CACHE_H */
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index 694c38db..f3cb9b59 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -38,7 +38,6 @@
#include "trans.h"
#include "util.h"
#include "log.h"
-#include "cache.h"
#include "deps.h"
pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2, const char *reason)
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index c8a91a2b..79d20d49 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -39,8 +39,9 @@
#include "log.h"
#include "util.h"
#include "handle.h"
-#include "cache.h"
#include "alpm.h"
+#include "package.h"
+#include "group.h"
/** \addtogroup alpm_databases Database Functions
* @brief Functions to query and manipulate the database of libalpm
@@ -80,7 +81,7 @@ pmdb_t SYMEXPORT *alpm_db_register_local(void)
}
/* Helper function for alpm_db_unregister{_all} */
-static void _alpm_db_unregister(pmdb_t *db)
+void _alpm_db_unregister(pmdb_t *db)
{
if(db == NULL) {
return;
@@ -96,6 +97,7 @@ static void _alpm_db_unregister(pmdb_t *db)
int SYMEXPORT alpm_db_unregister_all(void)
{
alpm_list_t *i;
+ pmdb_t *db;
ALPM_LOG_FUNC;
@@ -105,13 +107,16 @@ int SYMEXPORT alpm_db_unregister_all(void)
ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
/* close local database */
- _alpm_db_unregister(handle->db_local);
- handle->db_local = NULL;
+ db = handle->db_local;
+ if(db) {
+ db->ops->unregister(db);
+ handle->db_local = NULL;
+ }
/* and also sync ones */
for(i = handle->dbs_sync; i; i = i->next) {
- pmdb_t *db = i->data;
- _alpm_db_unregister(db);
+ db = i->data;
+ db->ops->unregister(db);
i->data = NULL;
}
FREELIST(handle->dbs_sync);
@@ -154,7 +159,7 @@ int SYMEXPORT alpm_db_unregister(pmdb_t *db)
RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
}
- _alpm_db_unregister(db);
+ db->ops->unregister(db);
return(0);
}
@@ -321,7 +326,7 @@ alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, const alpm_list_t* needles)
return(_alpm_db_search(db, needles));
}
-/* Set install reason for a package in db
+/** Set install reason for a package in db
* @param db pointer to the package database
* @param name the name of the package
* @param reason the new install reason
@@ -342,7 +347,7 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t
_alpm_log(PM_LOG_DEBUG, "setting install reason %u for %s/%s\n", reason, db->treename, name);
/* read DESC */
- if(_alpm_db_read(db, pkg, INFRQ_DESC)) {
+ if(_alpm_local_db_read(db, pkg, INFRQ_DESC)) {
return(-1);
}
if(pkg->reason == reason) {
@@ -352,7 +357,7 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t
/* set reason (in pkgcache) */
pkg->reason = reason;
/* write DESC */
- if(_alpm_db_write(db, pkg, INFRQ_DESC)) {
+ if(_alpm_local_db_write(db, pkg, INFRQ_DESC)) {
return(-1);
}
@@ -361,7 +366,7 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t
/** @} */
-static pmdb_t *_alpm_db_new(const char *treename, int is_local)
+pmdb_t *_alpm_db_new(const char *treename, int is_local)
{
pmdb_t *db;
@@ -409,10 +414,10 @@ const char *_alpm_db_path(pmdb_t *db)
CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
sprintf(db->_path, "%s%s/", dbpath, db->treename);
} else {
- pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 2;
+ pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 4;
CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
/* all sync DBs now reside in the sync/ subdir of the dbpath */
- sprintf(db->_path, "%ssync/%s/", dbpath, db->treename);
+ sprintf(db->_path, "%ssync/%s.db", dbpath, db->treename);
}
_alpm_log(PM_LOG_DEBUG, "database path for tree %s set to %s\n",
db->treename, db->_path);
@@ -503,52 +508,246 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
return(ret);
}
-pmdb_t *_alpm_db_register_local(void)
+/* Returns a new package cache from db.
+ * It frees the cache if it already exists.
+ */
+int _alpm_db_load_pkgcache(pmdb_t *db)
{
- pmdb_t *db;
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ return(-1);
+ }
+ _alpm_db_free_pkgcache(db);
+
+ _alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n",
+ db->treename);
+ if(db->ops->populate(db) == -1) {
+ _alpm_log(PM_LOG_DEBUG,
+ "failed to load package cache for repository '%s'\n", db->treename);
+ return(-1);
+ }
+ db->pkgcache_loaded = 1;
+ return(0);
+}
+
+void _alpm_db_free_pkgcache(pmdb_t *db)
+{
ALPM_LOG_FUNC;
- if(handle->db_local != NULL) {
- _alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n"));
- RET_ERR(PM_ERR_DB_NOT_NULL, NULL);
+ if(db == NULL || !db->pkgcache_loaded) {
+ return;
}
- _alpm_log(PM_LOG_DEBUG, "registering local database\n");
+ _alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n",
+ db->treename);
+
+ alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free);
+ alpm_list_free(db->pkgcache);
+ db->pkgcache_loaded = 0;
+
+ _alpm_db_free_grpcache(db);
+}
+
+alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
- db = _alpm_db_new("local", 1);
if(db == NULL) {
- RET_ERR(PM_ERR_DB_CREATE, NULL);
+ return(NULL);
}
- handle->db_local = db;
- return(db);
+ if(!db->pkgcache_loaded) {
+ _alpm_db_load_pkgcache(db);
+ }
+
+ /* hmmm, still NULL ?*/
+ if(!db->pkgcache) {
+ _alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename);
+ }
+
+ return(db->pkgcache);
}
-pmdb_t *_alpm_db_register_sync(const char *treename)
+/* "duplicate" pkg then add it to pkgcache */
+int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)
{
- pmdb_t *db;
- alpm_list_t *i;
+ pmpkg_t *newpkg;
ALPM_LOG_FUNC;
- for(i = handle->dbs_sync; i; i = i->next) {
- pmdb_t *sdb = i->data;
- if(strcmp(treename, sdb->treename) == 0) {
- _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
- return sdb;
+ if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
+ return(-1);
+ }
+
+ newpkg = _alpm_pkg_dup(pkg);
+ if(newpkg == NULL) {
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
+ alpm_pkg_get_name(newpkg), db->treename);
+ db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp);
+
+ _alpm_db_free_grpcache(db);
+
+ return(0);
+}
+
+int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg)
+{
+ void *vdata;
+ pmpkg_t *data;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
+ alpm_pkg_get_name(pkg), db->treename);
+
+ db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata);
+ data = vdata;
+ if(data == NULL) {
+ /* package not found */
+ _alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
+ alpm_pkg_get_name(pkg), db->treename);
+ return(-1);
+ }
+
+ _alpm_pkg_free(data);
+
+ _alpm_db_free_grpcache(db);
+
+ return(0);
+}
+
+pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target)
+{
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ return(NULL);
+ }
+
+ alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db);
+ if(!pkgcache) {
+ _alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n",
+ target);
+ return(NULL);
+ }
+
+ return(_alpm_pkg_find(pkgcache, target));
+}
+
+/* Returns a new group cache from db.
+ */
+int _alpm_db_load_grpcache(pmdb_t *db)
+{
+ alpm_list_t *lp;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n",
+ db->treename);
+
+ for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
+ const alpm_list_t *i;
+ pmpkg_t *pkg = lp->data;
+
+ for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
+ const char *grpname = i->data;
+ alpm_list_t *j;
+ pmgrp_t *grp = NULL;
+ int found = 0;
+
+ /* first look through the group cache for a group with this name */
+ for(j = db->grpcache; j; j = j->next) {
+ grp = j->data;
+
+ if(strcmp(grp->name, grpname) == 0
+ && !alpm_list_find_ptr(grp->packages, pkg)) {
+ grp->packages = alpm_list_add(grp->packages, pkg);
+ found = 1;
+ break;
+ }
+ }
+ if(found) {
+ continue;
+ }
+ /* we didn't find the group, so create a new one with this name */
+ grp = _alpm_grp_new(grpname);
+ grp->packages = alpm_list_add(grp->packages, pkg);
+ db->grpcache = alpm_list_add(db->grpcache, grp);
}
}
- _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
+ db->grpcache_loaded = 1;
+ return(0);
+}
+
+void _alpm_db_free_grpcache(pmdb_t *db)
+{
+ alpm_list_t *lg;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || !db->grpcache_loaded) {
+ return;
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n",
+ db->treename);
+
+ for(lg = db->grpcache; lg; lg = lg->next) {
+ _alpm_grp_free(lg->data);
+ lg->data = NULL;
+ }
+ FREELIST(db->grpcache);
+ db->grpcache_loaded = 0;
+}
+
+alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
- db = _alpm_db_new(treename, 0);
if(db == NULL) {
- RET_ERR(PM_ERR_DB_CREATE, NULL);
+ return(NULL);
}
- handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
- return(db);
+ if(!db->grpcache_loaded) {
+ _alpm_db_load_grpcache(db);
+ }
+
+ return(db->grpcache);
+}
+
+pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target)
+{
+ alpm_list_t *i;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || target == NULL || strlen(target) == 0) {
+ return(NULL);
+ }
+
+ for(i = _alpm_db_get_grpcache(db); i; i = i->next) {
+ pmgrp_t *info = i->data;
+
+ if(strcmp(info->name, target) == 0) {
+ return(info);
+ }
+ }
+
+ return(NULL);
}
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index 1851b5c9..5352e9ee 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -26,6 +26,10 @@
#include <limits.h>
#include <time.h>
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
/* Database entries */
typedef enum _pmdbinfrq_t {
INFRQ_BASE = 1,
@@ -33,12 +37,16 @@ typedef enum _pmdbinfrq_t {
INFRQ_DEPENDS = (1 << 2),
INFRQ_FILES = (1 << 3),
INFRQ_SCRIPTLET = (1 << 4),
- INFRQ_DELTAS = (1 << 5),
- INFRQ_DSIZE = (1 << 6),
+ INFRQ_DSIZE = (1 << 5),
/* ALL should be info stored in the package or database */
INFRQ_ALL = 0x3F
} pmdbinfrq_t;
+struct db_operations {
+ int (*populate) (pmdb_t *);
+ void (*unregister) (pmdb_t *);
+};
+
/* Database */
struct __pmdb_t {
char *treename;
@@ -46,12 +54,16 @@ struct __pmdb_t {
char *_path;
int pkgcache_loaded;
int grpcache_loaded;
+ /* also indicates whether we are RO or RW */
int is_local;
alpm_list_t *pkgcache;
alpm_list_t *grpcache;
alpm_list_t *servers;
+
+ struct db_operations *ops;
};
+
/* db.c, database general calls */
void _alpm_db_free(pmdb_t *db);
const char *_alpm_db_path(pmdb_t *db);
@@ -59,13 +71,33 @@ int _alpm_db_cmp(const void *d1, const void *d2);
alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);
pmdb_t *_alpm_db_register_local(void);
pmdb_t *_alpm_db_register_sync(const char *treename);
+void _alpm_db_unregister(pmdb_t *db);
+pmdb_t *_alpm_db_new(const char *treename, int is_local);
+
+/* be_*.c, backend specific calls */
+int _alpm_local_db_populate(pmdb_t *db);
+int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
+int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info);
+int _alpm_local_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
+int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info);
+
+int _alpm_sync_db_populate(pmdb_t *db);
+int _alpm_sync_db_read(pmdb_t *db, struct archive *archive, struct archive_entry *entry);
-/* be.c, backend specific calls */
-int _alpm_db_populate(pmdb_t *db);
-int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
-int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info);
-int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
-int _alpm_db_remove(pmdb_t *db, pmpkg_t *info);
+/* cache bullshit */
+/* packages */
+int _alpm_db_load_pkgcache(pmdb_t *db);
+void _alpm_db_free_pkgcache(pmdb_t *db);
+int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg);
+int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg);
+alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db);
+int _alpm_db_ensure_pkgcache(pmdb_t *db, pmdbinfrq_t infolevel);
+pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target);
+/* groups */
+int _alpm_db_load_grpcache(pmdb_t *db);
+void _alpm_db_free_grpcache(pmdb_t *db);
+alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db);
+pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target);
#endif /* _ALPM_DB_H */
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c
index fd893a63..0d8683c2 100644
--- a/lib/libalpm/deps.c
+++ b/lib/libalpm/deps.c
@@ -34,7 +34,6 @@
#include "graph.h"
#include "package.h"
#include "db.h"
-#include "cache.h"
#include "handle.h"
void _alpm_dep_free(pmdepend_t *dep)
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index 717d32ce..09bf78eb 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -42,7 +42,6 @@
#include "log.h"
#include "util.h"
#include "db.h"
-#include "cache.h"
#include "delta.h"
#include "handle.h"
#include "deps.h"
@@ -63,7 +62,7 @@ int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* Only free packages loaded in user space */
- if(pkg->origin != PKG_FROM_CACHE) {
+ if(pkg->origin == PKG_FROM_FILE) {
_alpm_pkg_free(pkg);
}
@@ -83,8 +82,7 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* We only inspect packages from sync repositories */
- ASSERT(pkg->origin == PKG_FROM_CACHE, RET_ERR(PM_ERR_PKG_INVALID, -1));
- ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1));
+ ASSERT(pkg->origin == PKG_FROM_SYNCDB, RET_ERR(PM_ERR_PKG_INVALID, -1));
fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg));
@@ -100,334 +98,194 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
return(retval);
}
+/* Default package accessor functions. These will get overridden by any
+ * backend logic that needs lazy access, such as the local database through
+ * a lazy-load cache. However, the defaults will work just fine for fully-
+ * populated package structures. */
+const char *_pkg_get_filename(pmpkg_t *pkg) { return pkg->filename; }
+const char *_pkg_get_name(pmpkg_t *pkg) { return pkg->name; }
+const char *_pkg_get_version(pmpkg_t *pkg) { return pkg->version; }
+const char *_pkg_get_desc(pmpkg_t *pkg) { return pkg->desc; }
+const char *_pkg_get_url(pmpkg_t *pkg) { return pkg->url; }
+time_t _pkg_get_builddate(pmpkg_t *pkg) { return pkg->builddate; }
+time_t _pkg_get_installdate(pmpkg_t *pkg) { return pkg->installdate; }
+const char *_pkg_get_packager(pmpkg_t *pkg) { return pkg->packager; }
+const char *_pkg_get_md5sum(pmpkg_t *pkg) { return pkg->md5sum; }
+const char *_pkg_get_arch(pmpkg_t *pkg) { return pkg->arch; }
+off_t _pkg_get_size(pmpkg_t *pkg) { return pkg->size; }
+off_t _pkg_get_isize(pmpkg_t *pkg) { return pkg->isize; }
+pmpkgreason_t _pkg_get_reason(pmpkg_t *pkg) { return pkg->reason; }
+int _pkg_has_force(pmpkg_t *pkg) { return pkg->force; }
+
+alpm_list_t *_pkg_get_licenses(pmpkg_t *pkg) { return pkg->licenses; }
+alpm_list_t *_pkg_get_groups(pmpkg_t *pkg) { return pkg->groups; }
+alpm_list_t *_pkg_get_depends(pmpkg_t *pkg) { return pkg->depends; }
+alpm_list_t *_pkg_get_optdepends(pmpkg_t *pkg) { return pkg->optdepends; }
+alpm_list_t *_pkg_get_conflicts(pmpkg_t *pkg) { return pkg->conflicts; }
+alpm_list_t *_pkg_get_provides(pmpkg_t *pkg) { return pkg->provides; }
+alpm_list_t *_pkg_get_replaces(pmpkg_t *pkg) { return pkg->replaces; }
+alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg) { return pkg->deltas; }
+alpm_list_t *_pkg_get_files(pmpkg_t *pkg) { return pkg->files; }
+alpm_list_t *_pkg_get_backup(pmpkg_t *pkg) { return pkg->backup; }
+
+/** The standard package operations struct. Get fields directly from the
+ * struct itself with no abstraction layer or any type of lazy loading.
+ */
+struct pkg_operations default_pkg_ops = {
+ .get_filename = _pkg_get_filename,
+ .get_name = _pkg_get_name,
+ .get_version = _pkg_get_version,
+ .get_desc = _pkg_get_desc,
+ .get_url = _pkg_get_url,
+ .get_builddate = _pkg_get_builddate,
+ .get_installdate = _pkg_get_installdate,
+ .get_packager = _pkg_get_packager,
+ .get_md5sum = _pkg_get_md5sum,
+ .get_arch = _pkg_get_arch,
+ .get_size = _pkg_get_size,
+ .get_isize = _pkg_get_isize,
+ .get_reason = _pkg_get_reason,
+ .has_force = _pkg_has_force,
+ .get_licenses = _pkg_get_licenses,
+ .get_groups = _pkg_get_groups,
+ .get_depends = _pkg_get_depends,
+ .get_optdepends = _pkg_get_optdepends,
+ .get_conflicts = _pkg_get_conflicts,
+ .get_provides = _pkg_get_provides,
+ .get_replaces = _pkg_get_replaces,
+ .get_deltas = _pkg_get_deltas,
+ .get_files = _pkg_get_files,
+ .get_backup = _pkg_get_backup,
+};
+
+/* Public functions for getting package information. These functions
+ * delegate the hard work to the function callbacks attached to each
+ * package, which depend on where the package was loaded from. */
const char SYMEXPORT *alpm_pkg_get_filename(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
-
- return pkg->filename;
+ return pkg->ops->get_filename(pkg);
}
const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)
{
- ASSERT(pkg != NULL, return(NULL));
- return pkg->name;
+ return pkg->ops->get_name(pkg);
}
const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)
{
- ASSERT(pkg != NULL, return(NULL));
- return pkg->version;
+ return pkg->ops->get_version(pkg);
}
const char SYMEXPORT *alpm_pkg_get_desc(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->desc;
+ return pkg->ops->get_desc(pkg);
}
const char SYMEXPORT *alpm_pkg_get_url(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->url;
+ return pkg->ops->get_url(pkg);
}
time_t SYMEXPORT alpm_pkg_get_builddate(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(0));
- ASSERT(pkg != NULL, return(0));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->builddate;
+ return pkg->ops->get_builddate(pkg);
}
time_t SYMEXPORT alpm_pkg_get_installdate(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(0));
- ASSERT(pkg != NULL, return(0));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->installdate;
+ return pkg->ops->get_installdate(pkg);
}
const char SYMEXPORT *alpm_pkg_get_packager(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->packager;
+ return pkg->ops->get_packager(pkg);
}
const char SYMEXPORT *alpm_pkg_get_md5sum(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->md5sum;
+ return pkg->ops->get_md5sum(pkg);
}
const char SYMEXPORT *alpm_pkg_get_arch(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->arch;
+ return pkg->ops->get_arch(pkg);
}
off_t SYMEXPORT alpm_pkg_get_size(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->size;
+ return pkg->ops->get_size(pkg);
}
off_t SYMEXPORT alpm_pkg_get_isize(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->isize;
+ return pkg->ops->get_isize(pkg);
}
pmpkgreason_t SYMEXPORT alpm_pkg_get_reason(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->reason;
+ return pkg->ops->get_reason(pkg);
}
-alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(pmpkg_t *pkg)
+int SYMEXPORT alpm_pkg_has_force(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->licenses;
+ return pkg->ops->has_force(pkg);
}
-alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->groups;
+ return pkg->ops->get_licenses(pkg);
}
-int SYMEXPORT alpm_pkg_has_force(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->force;
+ return pkg->ops->get_groups(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_depends(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_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->depends;
+ return pkg->ops->get_depends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(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_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->optdepends;
+ return pkg->ops->get_optdepends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(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_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->conflicts;
+ return pkg->ops->get_conflicts(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_provides(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_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->provides;
+ return pkg->ops->get_provides(pkg);
}
-alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(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;
+ return pkg->ops->get_replaces(pkg);
}
-alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
+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_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->replaces;
+ return pkg->ops->get_deltas(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_files(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->origin_data.db == handle->db_local
- && !(pkg->infolevel & INFRQ_FILES)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
- }
- return pkg->files;
+ return pkg->ops->get_files(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_backup(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->origin_data.db == handle->db_local
- && !(pkg->infolevel & INFRQ_FILES)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
- }
- return pkg->backup;
+ return pkg->ops->get_backup(pkg);
}
pmdb_t SYMEXPORT *alpm_pkg_get_db(pmpkg_t *pkg)
{
/* Sanity checks */
ASSERT(pkg != NULL, return(NULL));
- ASSERT(pkg->origin == PKG_FROM_CACHE, return(NULL));
+ ASSERT(pkg->origin != PKG_FROM_FILE, return(NULL));
return(pkg->origin_data.db);
}
@@ -441,49 +299,7 @@ pmdb_t SYMEXPORT *alpm_pkg_get_db(pmpkg_t *pkg)
*/
void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE) {
- char clfile[PATH_MAX];
- snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
- alpm_option_get_dbpath(),
- alpm_db_get_name(handle->db_local),
- alpm_pkg_get_name(pkg),
- alpm_pkg_get_version(pkg));
- return fopen(clfile, "r");
- } else if(pkg->origin == PKG_FROM_FILE) {
- struct archive *archive = NULL;
- struct archive_entry *entry;
- const char *pkgfile = pkg->origin_data.file;
-
- if((archive = archive_read_new()) == NULL) {
- RET_ERR(PM_ERR_LIBARCHIVE, NULL);
- }
-
- archive_read_support_compression_all(archive);
- archive_read_support_format_all(archive);
-
- if (archive_read_open_filename(archive, pkgfile,
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- RET_ERR(PM_ERR_PKG_OPEN, NULL);
- }
-
- while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
- const char *entry_name = archive_entry_pathname(entry);
-
- if(strcmp(entry_name, ".CHANGELOG") == 0) {
- return(archive);
- }
- }
- /* we didn't find a changelog */
- archive_read_finish(archive);
- errno = ENOENT;
- }
- return(NULL);
+ return pkg->ops->changelog_open(pkg);
}
/**
@@ -501,33 +317,13 @@ void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,
const pmpkg_t *pkg, const void *fp)
{
- size_t ret = 0;
- if(pkg->origin == PKG_FROM_CACHE) {
- ret = fread(ptr, 1, size, (FILE*)fp);
- } else if(pkg->origin == PKG_FROM_FILE) {
- ssize_t sret = archive_read_data((struct archive*)fp, ptr, size);
- /* Report error (negative values) */
- if(sret < 0) {
- pm_errno = PM_ERR_LIBARCHIVE;
- ret = 0;
- } else {
- ret = (size_t)sret;
- }
- }
- return(ret);
+ return pkg->ops->changelog_read(ptr, size, pkg, fp);
}
/*
int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
{
- int ret = 0;
- if(pkg->origin == PKG_FROM_CACHE) {
- ret = feof((FILE*)fp);
- } else if(pkg->origin == PKG_FROM_FILE) {
- // note: this doesn't quite work, no feof in libarchive
- ret = archive_read_data((struct archive*)fp, NULL, 0);
- }
- return(ret);
+ return pkg->ops->changelog_feof(pkg, fp);
}
*/
@@ -541,13 +337,7 @@ int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
*/
int SYMEXPORT alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp)
{
- int ret = 0;
- if(pkg->origin == PKG_FROM_CACHE) {
- ret = fclose((FILE*)fp);
- } else if(pkg->origin == PKG_FROM_FILE) {
- ret = archive_read_finish((struct archive *)fp);
- }
- return(ret);
+ return pkg->ops->changelog_close(pkg, fp);
}
int SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg)
@@ -558,9 +348,9 @@ int SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg)
ASSERT(handle != NULL, return(-1));
ASSERT(pkg != NULL, return(-1));
- if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
+ if(pkg->origin == PKG_FROM_LOCALDB
&& !(pkg->infolevel & INFRQ_SCRIPTLET)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);
+ _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);
}
return pkg->scriptlet;
}
@@ -667,6 +457,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
/* internal */
newpkg->origin = pkg->origin;
+ newpkg->ops = pkg->ops;
if(newpkg->origin == PKG_FROM_FILE) {
newpkg->origin_data.file = strdup(pkg->origin_data.file);
} else {
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index 14f81f92..5ad553ac 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -31,10 +31,65 @@
#include "db.h"
typedef enum _pmpkgfrom_t {
- PKG_FROM_CACHE = 1,
- PKG_FROM_FILE
+ PKG_FROM_FILE = 1,
+ PKG_FROM_LOCALDB,
+ PKG_FROM_SYNCDB
} pmpkgfrom_t;
+/** Package operations struct. This struct contains function pointers to
+ * all methods used to access data in a package to allow for things such
+ * as lazy package intialization (such as used by the file backend). Each
+ * backend is free to define a stuct containing pointers to a specific
+ * implementation of these methods. Some backends may find using the
+ * defined default_pkg_ops struct to work just fine for their needs.
+ */
+struct pkg_operations {
+ const char *(*get_filename) (pmpkg_t *);
+ const char *(*get_name) (pmpkg_t *);
+ const char *(*get_version) (pmpkg_t *);
+ const char *(*get_desc) (pmpkg_t *);
+ const char *(*get_url) (pmpkg_t *);
+ time_t (*get_builddate) (pmpkg_t *);
+ time_t (*get_installdate) (pmpkg_t *);
+ const char *(*get_packager) (pmpkg_t *);
+ const char *(*get_md5sum) (pmpkg_t *);
+ const char *(*get_arch) (pmpkg_t *);
+ off_t (*get_size) (pmpkg_t *);
+ off_t (*get_isize) (pmpkg_t *);
+ pmpkgreason_t (*get_reason) (pmpkg_t *);
+ int (*has_force) (pmpkg_t *);
+
+ alpm_list_t *(*get_licenses) (pmpkg_t *);
+ alpm_list_t *(*get_groups) (pmpkg_t *);
+ alpm_list_t *(*get_depends) (pmpkg_t *);
+ alpm_list_t *(*get_optdepends) (pmpkg_t *);
+ alpm_list_t *(*get_conflicts) (pmpkg_t *);
+ alpm_list_t *(*get_provides) (pmpkg_t *);
+ alpm_list_t *(*get_replaces) (pmpkg_t *);
+ alpm_list_t *(*get_deltas) (pmpkg_t *);
+ alpm_list_t *(*get_files) (pmpkg_t *);
+ alpm_list_t *(*get_backup) (pmpkg_t *);
+
+ void *(*changelog_open) (pmpkg_t *);
+ size_t (*changelog_read) (void *, size_t, const pmpkg_t *, const void *);
+ int (*changelog_close) (const pmpkg_t *, void *);
+
+ /* still to add:
+ * free()
+ * dup()
+ * checkmd5sum() ?
+ * has_scriptlet()
+ * compute_requiredby()
+ */
+};
+
+/** The standard package operations struct. get fields directly from the
+ * struct itself with no abstraction layer or any type of lazy loading.
+ * The actual definition is in package.c so it can have access to the
+ * default accessor functions which are defined there.
+ */
+extern struct pkg_operations default_pkg_ops;
+
struct __pmpkg_t {
char *filename;
char *name;
@@ -67,14 +122,16 @@ struct __pmpkg_t {
/* internal */
pmpkgfrom_t origin;
/* Replaced 'void *data' with this union as follows:
- origin == PKG_FROM_CACHE, use pkg->origin_data.db
origin == PKG_FROM_FILE, use pkg->origin_data.file
+ origin == PKG_FROM_*DB, use pkg->origin_data.db
*/
union {
pmdb_t *db;
char *file;
} origin_data;
pmdbinfrq_t infolevel;
+
+ struct pkg_operations *ops;
};
pmpkg_t* _alpm_pkg_new(void);
diff --git a/lib/libalpm/po/POTFILES.in b/lib/libalpm/po/POTFILES.in
index 475cf4b4..65637977 100644
--- a/lib/libalpm/po/POTFILES.in
+++ b/lib/libalpm/po/POTFILES.in
@@ -6,8 +6,9 @@ lib/libalpm/add.c
lib/libalpm/alpm.c
#lib/libalpm/alpm_list.c
lib/libalpm/backup.c
-lib/libalpm/be_files.c
+lib/libalpm/be_local.c
lib/libalpm/be_package.c
+lib/libalpm/be_sync.c
lib/libalpm/cache.c
lib/libalpm/conflict.c
lib/libalpm/db.c
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index dfaba03a..b53d85a6 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -42,7 +42,6 @@
#include "backup.h"
#include "package.h"
#include "db.h"
-#include "cache.h"
#include "deps.h"
#include "handle.h"
#include "alpm.h"
@@ -348,7 +347,7 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra
/* remove the package from the database */
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname);
- if(_alpm_db_remove(handle->db_local, oldpkg) == -1) {
+ if(_alpm_local_db_remove(handle->db_local, oldpkg) == -1) {
_alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),
pkgname, alpm_pkg_get_version(oldpkg));
}
@@ -443,7 +442,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
/* remove the package from the database */
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname);
- if(_alpm_db_remove(db, info) == -1) {
+ if(_alpm_local_db_remove(db, info) == -1) {
_alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),
pkgname, alpm_pkg_get_version(info));
}
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index f8193962..ab3d7871 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -39,7 +39,6 @@
#include "log.h"
#include "package.h"
#include "db.h"
-#include "cache.h"
#include "deps.h"
#include "conflict.h"
#include "trans.h"
@@ -832,7 +831,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
for(j = trans->add; j; j = j->next) {
pmpkg_t *spkg = j->data;
- if(spkg->origin == PKG_FROM_CACHE && current == spkg->origin_data.db) {
+ if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) {
const char *fname = NULL;
fname = alpm_pkg_get_filename(spkg);
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index 2e25b787..4dac5981 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -44,7 +44,6 @@
#include "sync.h"
#include "alpm.h"
#include "deps.h"
-#include "cache.h"
/** \addtogroup alpm_trans Transaction Functions
* @brief Functions to manipulate libalpm transactions
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index 5bf4ef12..26612418 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -800,4 +800,49 @@ char *_alpm_archive_fgets(char *line, size_t size, struct archive *a)
return(line);
}
+int _alpm_splitname(const char *target, pmpkg_t *pkg)
+{
+ /* the format of a db entry is as follows:
+ * package-version-rel/
+ * package name can contain hyphens, so parse from the back- go back
+ * two hyphens and we have split the version from the name.
+ */
+ char *tmp, *p, *q;
+
+ if(target == NULL || pkg == NULL) {
+ return(-1);
+ }
+ STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1));
+ p = tmp + strlen(tmp);
+
+ /* remove any trailing '/' */
+ while (*(p - 1) == '/') {
+ --p;
+ *p = '\0';
+ }
+
+ /* do the magic parsing- find the beginning of the version string
+ * by doing two iterations of same loop to lop off two hyphens */
+ for(q = --p; *q && *q != '-'; q--);
+ for(p = --q; *p && *p != '-'; p--);
+ if(*p != '-' || p == tmp) {
+ return(-1);
+ }
+
+ /* copy into fields and return */
+ if(pkg->version) {
+ FREE(pkg->version);
+ }
+ STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1));
+ /* insert a terminator at the end of the name (on hyphen)- then copy it */
+ *p = '\0';
+ if(pkg->name) {
+ FREE(pkg->name);
+ }
+ STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1));
+
+ free(tmp);
+ return(0);
+}
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h
index 35c4d288..75e2c45f 100644
--- a/lib/libalpm/util.h
+++ b/lib/libalpm/util.h
@@ -27,6 +27,7 @@
#include "config.h"
#include "alpm_list.h"
+#include "package.h" /* pmpkg_t */
#include <stdio.h>
#include <string.h>
@@ -76,6 +77,7 @@ const char *_alpm_filecache_setup(void);
int _alpm_lstat(const char *path, struct stat *buf);
int _alpm_test_md5sum(const char *filepath, const char *md5sum);
char *_alpm_archive_fgets(char *line, size_t size, struct archive *a);
+int _alpm_splitname(const char *target, pmpkg_t *pkg);
#ifndef HAVE_STRSEP
char *strsep(char **, const char *);