[pacman-dev] [PATCH 2/2] Added a new database backend

Sivert Berg sivertb at stud.ntnu.no
Mon Dec 15 04:20:55 EST 2008


This patch contains the changes and additions to libalpm. As you can see
minimal changes to the library was needed. The only change was making
the reading of changelog files happen through the database backend. I
also added an option to the configure script to choose which backend to
use (--with-backend).

Signed-off-by: Sivert Berg <sivertb at stud.ntnu.no>
---
 configure.ac            |    7 +
 lib/libalpm/Makefile.am |    2 +-
 lib/libalpm/be_files.c  |   21 ++
 lib/libalpm/be_packed.c |  845 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/libalpm/db.h        |    3 +
 lib/libalpm/package.c   |   12 +-
 6 files changed, 880 insertions(+), 10 deletions(-)
 create mode 100644 lib/libalpm/be_packed.c

diff --git a/configure.ac b/configure.ac
index c7841b8..6e28ac9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,6 +73,12 @@ AC_ARG_WITH(root-dir,
 	AS_HELP_STRING([--with-root-dir=path], [set the location of pacman's root operating directory]),
 	[ROOTDIR=$withval], [ROOTDIR=/])
 
+# Help line for database backend
+AC_ARG_WITH(backend,
+	AS_HELP_STRING([--with-backend=backend], [choose which backend to use. You can choose between 'files' and 'packed', it defaults to files]),
+	[BACKEND=$withval], [BACKEND=files])
+AC_SUBST(BACKEND)
+
 # Help line for package extension
 AC_ARG_WITH(pkg-ext,
 	AS_HELP_STRING([--with-pkg-ext=ext], [set the file extension used by packages]),
@@ -362,6 +368,7 @@ ${PACKAGE_NAME}:
     package extension      : ${PKGEXT}
     source pkg extension   : ${SRCEXT}
     database extension     : ${DBEXT}
+    database backend       : ${BACKEND}
 
   Compilation options:
     Run make in doc/ dir   : ${wantdoc}
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am
index 871855e..79b9d26 100644
--- a/lib/libalpm/Makefile.am
+++ b/lib/libalpm/Makefile.am
@@ -25,7 +25,7 @@ libalpm_la_SOURCES = \
 	alpm.h alpm.c \
 	alpm_list.h alpm_list.c \
 	backup.h backup.c \
-	be_files.c \
+	be_ at BACKEND@.c \
 	be_package.c \
 	cache.h cache.c \
 	conflict.h conflict.c \
diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c
index b9ff646..81d7a17 100644
--- a/lib/libalpm/be_files.c
+++ b/lib/libalpm/be_files.c
@@ -874,4 +874,25 @@ int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
 	return(ret);
 }
 
+void *_alpm_db_changelog_open(pmdb_t *db, pmpkg_t *pkg)
+{
+	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");
+}
+
+int _alpm_db_changelog_close(pmdb_t *db, void *stream)
+{
+	return fclose(stream);
+}
+
+size_t _alpm_db_changelog_read(pmdb_t *db, const void *pf, void *ptr, size_t size)
+{
+	return fread(ptr, 1, size, pf);
+}
+
 /* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/be_packed.c b/lib/libalpm/be_packed.c
new file mode 100644
index 0000000..3e4ea68
--- /dev/null
+++ b/lib/libalpm/be_packed.c
@@ -0,0 +1,845 @@
+/*
+ *  be_packed.c
+ *
+ *  Copyright (c) 2006 by Christian Hamar <krics at linuxforum.hu>
+ *  Copyright (c) 2006 by Miklos Vajna <vmiklos at frugalware.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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h> /* uintmax_t, intmax_t */
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <time.h>
+#include <utime.h>
+#include <limits.h> /* PATH_MAX */
+#include <locale.h> /* setlocale */
+
+/* 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 "delta.h"
+#include "deps.h"
+#include "dload.h"
+
+#include "be_packed.h"
+
+/** Update a package database
+ * @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, *dbfilepath;
+	time_t newmtime = 0;
+	char dbpath[PATH_MAX];
+	char dbname[PATH_MAX];
+	char buffer[1024];
+	size_t len;
+	struct stat st;
+	struct utimbuf utb;
+
+	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));
+	ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1));
+
+	if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
+		RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+	}
+
+	strncpy(dbname, db->path, PATH_MAX - 3);
+	/* Strip of the trailing / */
+	dbname[strlen(dbname) - 1] = '\0';
+	strcat(dbname, ".db");
+	stat(dbname, &st);
+
+	if(!force) {
+		/* get the lastupdate time */
+		if(st.st_mtime == 0) {
+			_alpm_log(PM_LOG_DEBUG, "failed to get last write time for %s\n",
+					db->treename);
+		}
+	}
+	else
+		st.st_mtime = 0;
+
+	len = strlen(db->treename) + strlen(DBEXT) + 1;
+	MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
+	sprintf(dbfile, "%s" DBEXT, db->treename);
+
+	strncpy(dbpath, alpm_option_get_dbpath(), PATH_MAX);
+	strcpy(dbpath + strlen(dbpath), "sync/");
+
+	ret = _alpm_download_single_file(dbfile, db->servers, dbpath,
+			st.st_mtime, &newmtime);
+	free(dbfile);
+
+	if(ret == 1) {
+		/* mtimes 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);
+	} else {
+		/* remove the old db */
+		_alpm_log(PM_LOG_DEBUG, "removing database %s\n", db->path);
+		unlink(dbname);
+
+		/* cache needs to be rebuilt */
+		_alpm_db_free_pkgcache(db);
+
+		/* form the path to the db location */
+		len = strlen(dbpath) + strlen(db->treename) + strlen(DBEXT) + 1;
+		MALLOC(dbfilepath, len, RET_ERR(PM_ERR_MEMORY, -1));
+		sprintf(dbfilepath, "%s%s" DBEXT, dbpath, db->treename);
+
+		/* convert the database file */
+		snprintf(buffer, 1024, "convdb %s", dbfilepath);
+		system(buffer);
+
+		/* set the correct time on the new database */
+		utb.actime = newmtime;
+		utb.modtime = newmtime;
+		utime(dbname, &utb);
+
+		/* Reopen the database */
+		_pack_db_close(db->handle);
+		db->handle = _pack_db_open(dbname);
+
+		unlink(dbfilepath);
+		free(dbfilepath);
+	}
+
+	return(0);
+}
+
+int _alpm_db_open(pmdb_t *db)
+{
+	ALPM_LOG_FUNC;
+	char path[PATH_MAX];
+
+	if(db == NULL) {
+		RET_ERR(PM_ERR_DB_NULL, -1);
+	}
+
+	strncpy(path, db->path, PATH_MAX - 3);
+	/* Strip of the trailing / */
+	path[strlen(path) - 1] = '\0';
+	strcat(path, ".db");
+
+	_alpm_log(PM_LOG_DEBUG, "opening database from path '%s'\n", db->path);
+	db->handle = _pack_db_open(path);
+
+	if(db->handle == NULL) {
+		RET_ERR(PM_ERR_DB_OPEN, -1);
+	}
+
+	return(0);
+}
+
+void _alpm_db_close(pmdb_t *db)
+{
+	ALPM_LOG_FUNC;
+
+	if(db == NULL) {
+		return;
+	}
+
+	if(db->handle) {
+		_pack_db_close(db->handle);
+		db->handle = NULL;
+	}
+}
+
+static int 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);
+
+	/* 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);
+}
+
+int _alpm_db_populate(pmdb_t *db)
+{
+	int count = 0;
+	int i;
+	char name[PATH_MAX];
+	pack_dir_t *dir;
+
+	ALPM_LOG_FUNC;
+
+	ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
+
+	dir = _pack_open_dir(db->handle);
+
+	while(_pack_dir_next(db->handle, dir, name, PATH_MAX) != -1) {
+		pmpkg_t *pkg;
+
+		pkg = _alpm_pkg_new();
+		if(pkg == NULL) {
+			return(-1);
+		}
+
+		/* Deal only with desc entries, that way we're sure we do
+		 * not add the same package twice
+		 */
+		if(strstr(name, "/desc") == NULL)
+			continue;
+
+		for (i = 0; name[i] && name[i] != '/'; i++);
+		name[i] = '\0';
+
+		/* split the db entry name */
+		if(splitname(name, pkg) != 0) {
+			_alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
+					name);
+			_alpm_pkg_free(pkg);
+			continue;
+		}
+
+		/* explicitly read with only 'BASE' data, accessors will handle the rest */
+		if(_alpm_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_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++;
+	}
+
+	db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp);
+	return(count);
+}
+
+int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
+{
+	char line[513];
+	char pkgname[PATH_MAX];
+	pack_file_t *pf;
+	ALPM_LOG_FUNC;
+
+	if(db == NULL) {
+		RET_ERR(PM_ERR_DB_NULL, -1);
+	}
+
+	if(info == NULL || info->name == NULL || info->version == NULL) {
+		_alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n");
+		return(-1);
+	}
+
+	if(info->origin == PKG_FROM_FILE) {
+		_alpm_log(PM_LOG_DEBUG, "request to read database info for a file-based package '%s', skipping...\n", info->name);
+		return(-1);
+	}
+
+	/* bitmask logic here:
+	 * infolevel: 00001111
+	 * inforeq:   00010100
+	 * & result:  00000100
+	 * == to inforeq? nope, we need to load more info. */
+	if((info->infolevel & inforeq) == inforeq) {
+		/* already loaded this info, do nothing */
+		return(0);
+	}
+	_alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n",
+			info->name, inforeq);
+
+	/* clear out 'line', to be certain - and to make valgrind happy */
+	memset(line, 0, 513);
+	snprintf(pkgname, PATH_MAX, "%s-%s", info->name, info->version);
+
+	/* DESC */
+	if(inforeq & INFRQ_DESC) {
+		if((pf = _pack_open_file(db->handle, pkgname, "desc", PO_READ)) == NULL) {
+			_alpm_log(PM_LOG_ERROR, _("could not open package %s\n"), pkgname);
+			goto error;
+		}
+		while(!_pack_file_eof(db->handle, pf)) {
+			if(_pack_file_gets(db->handle, pf, line, 256) == 0) {
+				break;
+			}
+			_alpm_strtrim(line);
+			if(strcmp(line, "%NAME%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				if(strcmp(_alpm_strtrim(line), info->name) != 0) {
+					_alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
+								"mismatch on package %s %s\n"), db->treename, info->name, line);
+				}
+			} else if(strcmp(line, "%VERSION%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				if(strcmp(_alpm_strtrim(line), info->version) != 0) {
+					_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(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				STRDUP(info->filename, _alpm_strtrim(line), goto error);
+			} else if(strcmp(line, "%DESC%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				STRDUP(info->desc, _alpm_strtrim(line), goto error);
+			} else if(strcmp(line, "%GROUPS%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->groups = alpm_list_add(info->groups, linedup);
+				}
+			} else if(strcmp(line, "%URL%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				STRDUP(info->url, _alpm_strtrim(line), goto error);
+			} else if(strcmp(line, "%LICENSE%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->licenses = alpm_list_add(info->licenses, linedup);
+				}
+			} else if(strcmp(line, "%ARCH%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				STRDUP(info->arch, _alpm_strtrim(line), goto error);
+			} else if(strcmp(line, "%BUILDDATE%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				_alpm_strtrim(line);
+
+				char first = tolower(line[0]);
+				if(first > 'a' && first < 'z') {
+					struct tm tmp_tm = {0}; //initialize to null incase of failure
+					setlocale(LC_TIME, "C");
+					strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+					info->builddate = mktime(&tmp_tm);
+					setlocale(LC_TIME, "");
+				} else {
+					info->builddate = atol(line);
+				}
+			} else if(strcmp(line, "%INSTALLDATE%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				_alpm_strtrim(line);
+
+				char first = tolower(line[0]);
+				if(first > 'a' && first < 'z') {
+					struct tm tmp_tm = {0}; //initialize to null incase of failure
+					setlocale(LC_TIME, "C");
+					strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+					info->installdate = mktime(&tmp_tm);
+					setlocale(LC_TIME, "");
+				} else {
+					info->installdate = atol(line);
+				}
+			} else if(strcmp(line, "%PACKAGER%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				STRDUP(info->packager, _alpm_strtrim(line), goto error);
+			} else if(strcmp(line, "%REASON%") == 0) {
+				if(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				info->reason = atol(_alpm_strtrim(line));
+			} else if(strcmp(line, "%SIZE%") == 0 || 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(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					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(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					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(_pack_file_gets(db->handle, pf, line, 512) == 0) {
+					goto error;
+				}
+				STRDUP(info->md5sum, _alpm_strtrim(line), goto error);
+			} else if(strcmp(line, "%REPLACES%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->replaces = alpm_list_add(info->replaces, linedup);
+				}
+			} else if(strcmp(line, "%FORCE%") == 0) {
+				info->force = 1;
+			}
+		}
+		_pack_close_file(pf);
+		pf = NULL;
+	}
+
+	/* FILES */
+	if(inforeq & INFRQ_FILES) {
+		if((pf = _pack_open_file(db->handle, pkgname, "files", PO_READ)) == NULL) {
+			_alpm_log(PM_LOG_ERROR, _("could not open package %s\n"), pkgname);
+			goto error;
+		}
+		while(_pack_file_gets(db->handle, pf, line, 256) &&
+			strlen(_alpm_strtrim(line))) {
+			_alpm_strtrim(line);
+			if(strcmp(line, "%FILES%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->files = alpm_list_add(info->files, linedup);
+				}
+			} else if(strcmp(line, "%BACKUP%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->backup = alpm_list_add(info->backup, linedup);
+				}
+			}
+		}
+		_pack_close_file(pf);
+		pf = NULL;
+	}
+
+	/* DEPENDS */
+	if(inforeq & INFRQ_DEPENDS) {
+		if((pf = _pack_open_file(db->handle, pkgname, "depends", PO_READ)) == NULL) {
+			_alpm_log(PM_LOG_ERROR, _("could not open package %s\n"), pkgname);
+			goto error;
+		}
+		while(!_pack_file_eof(db->handle, pf)) {
+			_pack_file_gets(db->handle, pf, line, 255);
+			_alpm_strtrim(line);
+			if(strcmp(line, "%DEPENDS%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line));
+					info->depends = alpm_list_add(info->depends, dep);
+				}
+			} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->optdepends = alpm_list_add(info->optdepends, linedup);
+				}
+			} else if(strcmp(line, "%CONFLICTS%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->conflicts = alpm_list_add(info->conflicts, linedup);
+				}
+			} else if(strcmp(line, "%PROVIDES%") == 0) {
+				while(_pack_file_gets(db->handle, pf, line, 512) &&
+						strlen(_alpm_strtrim(line))) {
+					char *linedup;
+					STRDUP(linedup, _alpm_strtrim(line), goto error);
+					info->provides = alpm_list_add(info->provides, linedup);
+				}
+			}
+		}
+		_pack_close_file(pf);
+		pf = NULL;
+	}
+
+	/* DELTAS */
+	if(inforeq & INFRQ_DELTAS) {
+		if((pf = _pack_open_file(db->handle, pkgname, "deltas", PO_READ)) != NULL) {
+			while(!_pack_file_eof(db->handle, pf)) {
+				_pack_file_gets(db->handle, pf, line, 255);
+				_alpm_strtrim(line);
+				if(strcmp(line, "%DELTAS%") == 0) {
+					while(_pack_file_gets(db->handle, pf, line, 512) &&
+							strlen(_alpm_strtrim(line))) {
+						pmdelta_t *delta = _alpm_delta_parse(line);
+						if(delta) {
+							info->deltas = alpm_list_add(info->deltas, delta);
+						}
+					}
+				}
+			}
+			_pack_close_file(pf);
+			pf = NULL;
+		}
+	}
+	/* INSTALL */
+	if(inforeq & INFRQ_SCRIPTLET) {
+		if((pf = _pack_open_file(db->handle, pkgname, "depends", PO_READ)) != NULL) {
+			info->scriptlet = 1;
+			_pack_close_file(pf);
+		}
+	}
+
+	/* internal */
+	info->infolevel |= inforeq;
+
+	return(0);
+
+error:
+	if(pf) {
+		_pack_close_file(pf);
+	}
+	return(-1);
+}
+
+int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
+{
+	char pkgname[PATH_MAX];
+	alpm_list_t *lp = NULL;
+	int retval = 0;
+	int local = 0;
+	pack_file_t *pf;
+	char buffer[1024];
+	size_t len;
+
+	ALPM_LOG_FUNC;
+
+	if(db == NULL || info == NULL) {
+		return(-1);
+	}
+
+	if(strcmp(db->treename, "local") == 0) {
+		local = 1;
+	}
+
+	snprintf(pkgname, PATH_MAX, "%s-%s", info->name, info->version);
+
+	/* DESC */
+	if(inforeq & INFRQ_DESC) {
+		_alpm_log(PM_LOG_DEBUG, "writing %s-%s DESC information back to db\n",
+				info->name, info->version);
+		if((pf = _pack_open_file(db->handle, pkgname, "desc", PO_WRITE)) == NULL) {
+			_alpm_log(PM_LOG_ERROR, _("could not open package %s\n"), pkgname);
+			retval = -1;
+			goto cleanup;
+		}
+
+		len = snprintf(buffer, 1024, "%%NAME%%\n%s\n\n"
+						"%%VERSION%%\n%s\n\n", info->name, info->version);
+		_pack_file_puts(db->handle, pf, buffer, len);
+		if(info->desc) {
+			len = snprintf(buffer, 1024, "%%DESC%%\n"
+							"%s\n\n", info->desc);
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(info->groups) {
+			_pack_file_puts(db->handle, pf, "%GROUPS%\n", 9);
+			for(lp = info->groups; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			_pack_file_puts(db->handle, pf, "\n", 1);
+		}
+		if(info->replaces) {
+			_pack_file_puts(db->handle, pf, "%REPLACES%\n", 11);
+			for(lp = info->replaces; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(info->force) {
+			len = snprintf(buffer, 1024, "%%FORCE%%\n\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(local) {
+			if(info->url) {
+				len = snprintf(buffer, 1024, "%%URL%%\n"
+								"%s\n\n", info->url);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->licenses) {
+				_pack_file_puts(db->handle, pf, "%LICENSE%\n", 10);
+				for(lp = info->licenses; lp; lp = lp->next) {
+					len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+					_pack_file_puts(db->handle, pf, buffer, len);
+				}
+				len = snprintf(buffer, 1024, "\n");
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->arch) {
+				len = snprintf(buffer, 1024, "%%ARCH%%\n"
+								"%s\n\n", info->arch);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->builddate) {
+				len = snprintf(buffer, 1024, "%%BUILDDATE%%\n"
+								"%ju\n\n", (uintmax_t)info->builddate);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->installdate) {
+				len = snprintf(buffer, 1024, "%%INSTALLDATE%%\n"
+								"%ju\n\n", (uintmax_t)info->installdate);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->packager) {
+				len = snprintf(buffer, 1024, "%%PACKAGER%%\n"
+								"%s\n\n", info->packager);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->isize) {
+				/* only write installed size, csize is irrelevant once installed */
+				len = snprintf(buffer, 1024, "%%SIZE%%\n"
+								"%ju\n\n", (intmax_t)info->isize);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->reason) {
+				len = snprintf(buffer, 1024, "%%REASON%%\n"
+								"%u\n\n", info->reason);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+		} else {
+			if(info->size) {
+				len = snprintf(buffer, 1024, "%%CSIZE%%\n"
+								"%ju\n\n", (intmax_t)info->size);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->isize) {
+				len = snprintf(buffer, 1024, "%%ISIZE%%\n"
+								"%ju\n\n", (intmax_t)info->isize);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			if(info->md5sum) {
+				len = snprintf(buffer, 1024, "%%MD5SUM%%\n"
+								"%s\n\n", info->md5sum);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+		}
+		_pack_close_file(pf);
+		pf = NULL;
+	}
+
+	/* FILES */
+	if(local && (inforeq & INFRQ_FILES)) {
+		_alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n",
+				info->name, info->version);
+		if((pf = _pack_open_file(db->handle, pkgname, "files", PO_WRITE)) == NULL) {
+			_alpm_log(PM_LOG_ERROR, _("could not open package %s\n"), pkgname);
+			retval = -1;
+			goto cleanup;
+		}
+
+		if(info->files) {
+			len = snprintf(buffer, 1024, "%%FILES%%\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+			for(lp = info->files; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(info->backup) {
+			len = snprintf(buffer, 1024, "%%BACKUP%%\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+			for(lp = info->backup; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		_pack_close_file(pf);
+		pf = NULL;
+	}
+
+	/* DEPENDS */
+	if(inforeq & INFRQ_DEPENDS) {
+		_alpm_log(PM_LOG_DEBUG, "writing %s-%s DEPENDS information back to db\n",
+				info->name, info->version);
+		if((pf = _pack_open_file(db->handle, pkgname, "depends", PO_WRITE)) == NULL) {
+			_alpm_log(PM_LOG_ERROR, _("could not open package %s\n"), pkgname);
+			retval = -1;
+			goto cleanup;
+		}
+
+		if(info->depends) {
+			_pack_file_puts(db->handle, pf, "%DEPENDS%\n", 10);
+			for(lp = info->depends; lp; lp = lp->next) {
+				char *depstring = alpm_dep_get_string(lp->data);
+				len = snprintf(buffer, 1024, "%s\n", depstring);
+				_pack_file_puts(db->handle, pf, buffer, len);
+				free(depstring);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(info->optdepends) {
+			_pack_file_puts(db->handle, pf, "%OPTDEPENDS%\n", 13);
+			for(lp = info->optdepends; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(info->conflicts) {
+			_pack_file_puts(db->handle, pf, "%CONFLICTS%\n", 12);
+			for(lp = info->conflicts; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		if(info->provides) {
+			_pack_file_puts(db->handle, pf, "%PROVIDES%\n", 11);
+			for(lp = info->provides; lp; lp = lp->next) {
+				len = snprintf(buffer, 1024, "%s\n", (char *)lp->data);
+				_pack_file_puts(db->handle, pf, buffer, len);
+			}
+			len = snprintf(buffer, 1024, "\n");
+			_pack_file_puts(db->handle, pf, buffer, len);
+		}
+		_pack_close_file(pf);
+		pf = NULL;
+	}
+
+	/* INSTALL */
+	/* nothing needed here (script is automatically extracted) */
+
+cleanup:
+	if(pf) {
+		_pack_close_file(pf);
+	}
+
+	return(retval);
+}
+
+int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
+{
+	int ret = 0;
+	char pkgname[512];
+
+	ALPM_LOG_FUNC;
+
+	snprintf(pkgname, 512, "%s-%s", info->name, info->version);
+	_pack_package_remove(db->handle, pkgname);
+
+	if(db == NULL || info == NULL) {
+		RET_ERR(PM_ERR_DB_NULL, -1);
+	}
+
+	return(ret);
+}
+
+void *_alpm_db_changelog_open(pmdb_t *db, pmpkg_t *pkg)
+{
+	char name[512];
+	snprintf(name, 512, "%s-%s", pkg->name, pkg->version);
+	return _pack_open_file(db->handle, name, "changelog", PO_READ);
+}
+
+int _alpm_db_changelog_close(pmdb_t *db, void *stream)
+{
+	_pack_close_file(stream);
+	return 0;
+}
+
+size_t _alpm_db_changelog_read(pmdb_t *db, const void *pf, void *ptr, size_t size)
+{
+	return _pack_file_gets(db->handle, pf, ptr, size);
+}
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index 96fac0d..96291fc 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -62,6 +62,9 @@ int _alpm_db_populate(pmdb_t *db);
 int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
 int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
 int _alpm_db_remove(pmdb_t *db, pmpkg_t *info);
+void *_alpm_db_changelog_open(pmdb_t *db, pmpkg_t *pkg);
+int _alpm_db_changelog_close(pmdb_t *db, void *stream);
+size_t _alpm_db_changelog_read(pmdb_t *db, const void *pf, void *ptr, size_t size);
 
 #endif /* _ALPM_DB_H */
 
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index ee0ff6f..7ab9710 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -447,13 +447,7 @@ void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
 	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");
+		return(_alpm_db_changelog_open(handle->db_local, pkg));
 	} else if(pkg->origin == PKG_FROM_FILE) {
 		struct archive *archive = NULL;
 		struct archive_entry *entry;
@@ -500,7 +494,7 @@ size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,
 {
 	size_t ret = 0;
 	if(pkg->origin == PKG_FROM_CACHE) {
-		ret = fread(ptr, 1, size, (FILE*)fp);
+		ret = _alpm_db_changelog_read(handle->db_local, fp, ptr, size);
 	} else if(pkg->origin == PKG_FROM_FILE) {
 		ret = archive_read_data((struct archive*)fp, ptr, size);
 	}
@@ -533,7 +527,7 @@ 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);
+		ret = _alpm_db_changelog_close(handle->db_local, fp);
 	} else if(pkg->origin == PKG_FROM_FILE) {
 		ret = archive_read_finish((struct archive *)fp);
 	}
-- 
1.6.0.5



More information about the pacman-dev mailing list