On So, 2014-02-02 at 14:06 +0100, Bernhard R. Link wrote:
> * Benjamin Drung <[email protected]> [140108 15:51]:
> 
> First sorry for my late reply. I must have totally missed your mail.

No problem. I have been kept busy with other projects. ;)

> > The first step is to agree on the database layout change. I came up with
> > two alternatives:
> >
> > 1) Allow duplicate entries in packages.db and sort duplicate entries by
> > their Debian version. They can be sorted a) upwards or b) downwards.
> > Depending on the request, we will either search for all versions of a
> > package, one specific version of the package, or for the latest version
> > of a package.
> >
> > 2) Rename the key of packages.db to also contain the version of the
> > package, e.g. "sl|3.03-17" or "hello_2.8-4" (which delimiter should we
> > use?). This would allow us to check directly for a specific version of a
> > package. We need to add a secondary table that allows us to access the
> > database as described in 1) through the secondary table. This secondary
> > table will allow duplicate entries and the values of the secondary table
> > point to the key in packages.db. Depending on the task, we either query
> > the first or secondary table. The secondary table will be kept in sync
> > by BerkeleyDB.
> >
> > In the first case, we need to add a function to iterate over the
> > duplicate packages to find a specific version. In the second case, we
> > need to create the secondary table and transform the database.
> >
> > Which layout do you prefer?
> 
> I think that layout is better that better fits the code. Not yet having
> looked at the code, I cannot say. I guess 1 might be simpler. In the
> case of 2 I think "|" is fine, as it is already used elsewhere (though
> I guess one should make sure reprepro does not allow | in package
> names).

Okay. Attached the patch for my prototype. Be aware: It's just a
prototype that is just able to run the commands that I wanted to test,
but isn't near to be ready for mainlining. The prototype implements case
2 just because that was my initial idea, but now I tend to think that
case 1 might be easier/cleaner.

> > Another issue is the sorting of the packages in the database. We need
> > one function to sort all entries in the table. So we need one function
> > to sort binary packages and source packages, but we have
> > binaries_getversion() and source_getversion(). Here's the example code
> > (without the error handling) of the sorting function:
> > 
> > static int debianversioncompare(UNUSED(DB *db), const DBT *a, const DBT *b) 
> > {
> >     char *a_version, *b_version;
> >     int versioncmp;
> > 
> >     binaries_getversion(a->data, &a_version);
> >     binaries_getversion(b->data, &b_version);
> >     dpkgversions_cmp(a_version, b_version, &versioncmp);
> >     return versioncmp;
> > }
> > 
> > Do you have a suggestion how to improve this function?
> 
> It sounds quite slow either way. Perhaps the way to go is instead
> changing the data format, like having the version first (perhaps even in
> preparsed format to speed things up).

Good idea, but is this function really time critical? It should be only
called when comparing duplicate keys (which shouldn't happen that often,
does it?). How do you want to preparse the version?

How would the data format change? Currently the database value contains
just the control junk. We could put the pair (version, control) as value
into the database. How should the pair separated? Maybe with a null
character? Then we could just use the pointer to the value as version
string (the null character from the pair separation would also be used
to terminate the string).

-- 
Benjamin Drung
System Developer

ProfitBricks GmbH - The IaaS-Company
Greifswalder Str. 207
D - 10405 Berlin

Mail: [email protected]
Fax:  +49 30 577 008 598
URL:  http://www.profitbricks.com

Sitz der Gesellschaft: Berlin.
Registergericht: Amtsgericht Charlottenburg, HRB 125506 B.
Geschäftsführer: Andreas Gauger, Achim Weiss.
diff --git a/binaries.c b/binaries.c
index e66803d..74b4224 100644
--- a/binaries.c
+++ b/binaries.c
@@ -216,6 +216,20 @@ static inline retvalue calcnewcontrol(const char *chunk, const char *packagename
 	return RET_OK;
 }
 
+retvalue binaries_getpackage(const char *control, char **package) {
+	retvalue r;
+
+	r = chunk_getvalue(control, "Package", package);
+	if (RET_WAS_ERROR(r))
+		return r;
+	if (r == RET_NOTHING) {
+		fprintf(stderr, "Missing 'Package' field in chunk:'%s'\n",
+				control);
+		return RET_ERROR;
+	}
+	return r;
+}
+
 retvalue binaries_getversion(const char *control, char **version) {
 	retvalue r;
 
diff --git a/binaries.h b/binaries.h
index ff1a9e6..a44bfe1 100644
--- a/binaries.h
+++ b/binaries.h
@@ -14,6 +14,7 @@
 
 
 /* Functions for the target.h-stuff: */
+get_package binaries_getpackage;
 get_version binaries_getversion;
 get_installdata binaries_getinstalldata;
 get_architecture binaries_getarchitecture;
diff --git a/chunks.c b/chunks.c
index ca1fd9e..82ae15a 100644
--- a/chunks.c
+++ b/chunks.c
@@ -120,6 +120,35 @@ retvalue chunk_getvalue(const char *chunk, const char *name, char **value) {
 	return RET_OK;
 }
 
+/* look for name in chunk. returns RET_NOTHING if not found */
+retvalue chunk_getvalue_pointer(const char *chunk, const char *name, char **value, size_t *size) {
+	const char *field;
+	const char *b, *e;
+
+	assert(value != NULL);
+	field = chunk_getfield(name, chunk);
+	if (field == NULL)
+		return RET_NOTHING;
+
+	b = field;
+	/* jump over spaces at the beginning */
+	if (xisspace(*b))
+		b++;
+	/* search for the end */
+	e = b;
+	while (*e != '\n' && *e != '\0')
+		e++;
+	/* remove trailing spaces */
+	while (e > b && xisspace(*e))
+		e--;
+	if (!xisspace(*e))
+		*size = e - b + 1;
+	else
+		*size = 0;
+	*value = b;
+	return RET_OK;
+}
+
 retvalue chunk_getextralinelist(const char *chunk, const char *name, struct strlist *strlist) {
 	retvalue r;
 	const char *f, *b, *e;
diff --git a/chunks.h b/chunks.h
index 314170a..663f6b1 100644
--- a/chunks.h
+++ b/chunks.h
@@ -11,6 +11,7 @@
 
 /* look for name in chunk. returns RET_NOTHING if not found */
 retvalue chunk_getvalue(const char *, const char *, /*@out@*/char **);
+retvalue chunk_getvalue_pointer(const char *, const char *, /*@out@*/char **, /*@out@*/size_t *);
 retvalue chunk_getextralinelist(const char *, const char *, /*@out@*/struct strlist *);
 retvalue chunk_getwordlist(const char *, const char *, /*@out@*/struct strlist *);
 retvalue chunk_getuniqwordlist(const char *, const char *, /*@out@*/struct strlist *);
diff --git a/database.c b/database.c
index df18472..ffba680 100644
--- a/database.c
+++ b/database.c
@@ -33,6 +33,7 @@
 #include "ignore.h"
 #include "strlist.h"
 #include "names.h"
+#include "chunks.h"
 #include "database.h"
 #include "dirs.h"
 #include "filecntl.h"
@@ -211,16 +212,17 @@ static retvalue database_hasdatabasefile(const char *filename, /*@out@*/bool *ex
 
 enum database_type {
 	dbt_QUERY,
-	dbt_BTREE, dbt_BTREEDUP, dbt_BTREEPAIRS,
+	dbt_BTREE, dbt_BTREEDUP, dbt_BTREEPAIRS, dbt_BTREEVERSIONS,
 	dbt_HASH,
 	dbt_COUNT /* must be last */
 };
 static const uint32_t types[dbt_COUNT] = {
 	DB_UNKNOWN,
-	DB_BTREE, DB_BTREE, DB_BTREE,
+	DB_BTREE, DB_BTREE, DB_BTREE, DB_BTREE,
 	DB_HASH
 };
 
+static int debianversioncompare(UNUSED(DB *db), const DBT *a, const DBT *b);
 static int paireddatacompare(UNUSED(DB *db), const DBT *a, const DBT *b);
 
 static retvalue database_opentable(const char *filename, /*@null@*/const char *subtable, enum database_type type, uint32_t flags, /*@out@*/DB **result) {
@@ -238,7 +240,7 @@ static retvalue database_opentable(const char *filename, /*@null@*/const char *s
 		free(fullfilename);
 		return RET_DBERR(dbret);
 	}
-	if (type == dbt_BTREEDUP || type == dbt_BTREEPAIRS) {
+	if (type == dbt_BTREEDUP || type == dbt_BTREEPAIRS || type == dbt_BTREEVERSIONS) {
 		dbret = table->set_flags(table, DB_DUPSORT);
 		if (dbret != 0) {
 			table->err(table, dbret, "db_set_flags(DB_DUPSORT):");
@@ -256,6 +258,15 @@ static retvalue database_opentable(const char *filename, /*@null@*/const char *s
 			return RET_DBERR(dbret);
 		}
 	}
+	if (type == dbt_BTREEVERSIONS) {
+		dbret = table->set_dup_compare(table, debianversioncompare);
+		if (dbret != 0) {
+			table->err(table, dbret, "db_set_dup_compare:");
+			(void)table->close(table, 0);
+			free(fullfilename);
+			return RET_DBERR(dbret);
+		}
+	}
 
 #if DB_VERSION_MAJOR == 5
 #define DB_OPEN(database, filename, name, type, flags) \
@@ -944,6 +955,7 @@ static const char databaseerror[] = "Internal error of the underlying BerkeleyDB
 struct table {
 	char *name, *subname;
 	DB *berkeleydb;
+	DB *sec_berkeleydb;
 	bool *flagreset;
 	bool readonly, verbose;
 };
@@ -968,6 +980,10 @@ retvalue table_close(struct table *table) {
 		return RET_NOTHING;
 	if (table->flagreset != NULL)
 		*table->flagreset = false;
+	if (table->sec_berkeleydb != NULL) {
+		dbret = table->sec_berkeleydb->close(table->sec_berkeleydb, 0);
+		// FIXME: Error handling
+	}
 	if (table->berkeleydb == NULL) {
 		assert (table->readonly);
 		dbret = 0;
@@ -1293,6 +1309,40 @@ struct cursor {
 	retvalue r;
 };
 
+retvalue table_sec_newglobalcursor(struct table *table, struct cursor **cursor_p) {
+	struct cursor *cursor;
+	int dbret;
+	DB *berkeleydb;
+
+	berkeleydb = table->berkeleydb;
+	if (table->sec_berkeleydb != NULL) {
+		berkeleydb = table->sec_berkeleydb;
+	}
+
+	if (berkeleydb == NULL) {
+		assert (table->readonly);
+		*cursor_p = NULL;
+		return RET_OK;
+	}
+
+	cursor = zNEW(struct cursor);
+	if (FAILEDTOALLOC(cursor))
+		return RET_ERROR_OOM;
+
+	cursor->cursor = NULL;
+	cursor->flags = DB_NEXT;
+	cursor->r = RET_OK;
+	dbret = berkeleydb->cursor(berkeleydb, NULL,
+			&cursor->cursor, 0);
+	if (dbret != 0) {
+		table_printerror(table, dbret, "cursor");
+		free(cursor);
+		return RET_DBERR(dbret);
+	}
+	*cursor_p = cursor;
+	return RET_OK;
+}
+
 retvalue table_newglobalcursor(struct table *table, struct cursor **cursor_p) {
 	struct cursor *cursor;
 	int dbret;
@@ -1758,6 +1808,43 @@ static int paireddatacompare(UNUSED(DB *db), const DBT *a, const DBT *b) {
 		return strncmp(a->data, b->data, b->size);
 }
 
+static int debianversioncompare(UNUSED(DB *db), const DBT *a, const DBT *b) {
+	char *a_version;
+	char *b_version;
+	int versioncmp;
+	retvalue r;
+
+	//printf("*** debianversioncompare() called.\n");
+	// FIXME propper error handling
+
+	r = binaries_getversion(a->data, &a_version);
+	if (RET_WAS_ERROR(r)) {
+		fprintf(stderr, "Error parsing old version!\n");
+		return r;
+	}
+
+	r = binaries_getversion(b->data, &b_version);
+	if (RET_WAS_ERROR(r)) {
+		fprintf(stderr, "Error parsing old version!\n");
+		free(a_version);
+		return r;
+	}
+
+	r = dpkgversions_cmp(a_version, b_version, &versioncmp);
+	if (RET_WAS_ERROR(r)) {
+		fprintf(stderr, "Parse errors processing versions.\n");
+		free(a_version);
+		free(b_version);
+		return r;
+	}
+
+	//printf("*** compare %s with %s: %i\n", a_version, b_version, versioncmp);
+
+	free(a_version);
+	free(b_version);
+	return versioncmp;
+}
+
 retvalue database_opentracking(const char *codename, bool readonly, struct table **table_p) {
 	struct table *table;
 	retvalue r;
@@ -1786,8 +1873,25 @@ retvalue database_opentracking(const char *codename, bool readonly, struct table
 	return RET_OK;
 }
 
+int get_package_name(DB *secondary, const DBT *pkey, const DBT *pdata, DBT *skey) {
+	char *name;
+	retvalue r;
+
+	memset(skey, 0, sizeof(DBT));
+	r = chunk_getvalue_pointer((const char *)pdata->data, "Package", &skey->data, &skey->size);
+	if (RET_WAS_ERROR(r)) {
+		fprintf(stderr, "FIXME\n");
+		return -1;
+	}
+	chunk_getvalue((const char *)pdata->data, "Package", &name);
+	//printf("FIXME: added %s to %s\n", name, pkey->data);
+	return 0;
+}
+
+
 retvalue database_openpackages(const char *identifier, bool readonly, struct table **table_p) {
 	struct table *table;
+	struct table *secondary_table;
 	retvalue r;
 
 	if (rdb_nopackages) {
@@ -1809,6 +1913,21 @@ retvalue database_openpackages(const char *identifier, bool readonly, struct tab
 	assert (r != RET_NOTHING);
 	if (RET_WAS_ERROR(r))
 		return r;
+
+	r = database_table("packages.secondary.db", identifier,
+			dbt_BTREEVERSIONS, readonly?DB_RDONLY:DB_CREATE, &secondary_table);
+	assert (r != RET_NOTHING);
+	if (RET_WAS_ERROR(r))
+		return r;
+
+	r = table->berkeleydb->associate(table->berkeleydb, NULL,
+			secondary_table->berkeleydb, get_package_name, 0);
+	if (r != 0) {
+		fprintf(stderr, "FIMXE: associate failed.\n");
+		return RET_ERROR;
+	}
+
+	table->sec_berkeleydb = secondary_table->berkeleydb;
 	table->flagreset = &rdb_packagesdatabaseopen;
 	rdb_packagesdatabaseopen = true;
 	*table_p = table;
diff --git a/distribution.c b/distribution.c
index 6db17da..9d12293 100644
--- a/distribution.c
+++ b/distribution.c
@@ -531,6 +531,7 @@ retvalue distribution_foreach_package(struct distribution *distribution, const s
 			if (r == RET_NOTHING)
 				continue;
 		}
+		// FIXME: test: r = target_sec_openiterator(t, READONLY, &iterator);
 		r = target_openiterator(t, READONLY, &iterator);
 		RET_UPDATE(result, r);
 		if (RET_WAS_ERROR(r))
diff --git a/main.c b/main.c
index 2965341..d207631 100644
--- a/main.c
+++ b/main.c
@@ -1157,8 +1157,7 @@ static retvalue list_in_target(struct target *target, const char *packagename) {
 	result = table_getrecord(target->packages, packagename, &control);
 	if (RET_IS_OK(result)) {
 		if (listskip <= 0) {
-			r = listformat_print(listformat, target,
-					packagename, control);
+			r = listformat_print(listformat, target, control);
 			RET_UPDATE(result, r);
 			if (listmax > 0)
 				listmax--;
@@ -1178,7 +1177,7 @@ static retvalue list_package(UNUSED(struct distribution *dummy2), struct target
 	if (listskip <= 0) {
 		if (listmax > 0)
 			listmax--;
-		return listformat_print(listformat, target, package, control);
+		return listformat_print(listformat, target, control);
 	} else {
 		listskip--;
 		return RET_NOTHING;
@@ -1403,8 +1402,7 @@ static retvalue listfilterprint(UNUSED(struct distribution *di), struct target *
 		if (listskip <= 0) {
 			if (listmax > 0)
 				listmax--;
-			r = listformat_print(listformat, target,
-					packagename, control);
+			r = listformat_print(listformat, target, control);
 		} else {
 			listskip--;
 			r = RET_NOTHING;
@@ -1447,8 +1445,7 @@ static retvalue listmatchprint(UNUSED(struct distribution *di), struct target *t
 		if (listskip <= 0) {
 			if (listmax > 0)
 				listmax--;
-			return listformat_print(listformat, target,
-					packagename, control);
+			return listformat_print(listformat, target, control);
 		} else {
 			listskip--;
 			return RET_NOTHING;
diff --git a/printlistformat.c b/printlistformat.c
index d16d016..0ebe6a4 100644
--- a/printlistformat.c
+++ b/printlistformat.c
@@ -32,9 +32,17 @@
 #include "printlistformat.h"
 #include "dirs.h"
 
-retvalue listformat_print(const char *listformat, const struct target *target, const char *package, const char *control) {
+retvalue listformat_print(const char *listformat, const struct target *target, const char *control) {
 	retvalue r;
 	const char *p, *q;
+	char *package;
+
+	r = target->getpackage(control, &package);
+	if (!RET_IS_OK(r)) {
+		printf("Could not retrieve package name in %s\n",
+				target->identifier);
+		return r;
+	}
 
 	if (listformat == NULL) {
 		char *version;
@@ -48,6 +56,7 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 			printf("Could not retrieve version from %s in %s\n",
 					package, target->identifier);
 		}
+		free(package);
 		return r;
 	}
 	/* try to produce the same output dpkg-query --show produces: */
@@ -102,8 +111,10 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 		           || (q - p ==  9 && strncasecmp(p, "{$filekey", 9) == 0)) {
 			struct strlist filekeys;
 			r = target->getfilekeys(control, &filekeys);
-			if (RET_WAS_ERROR(r))
+			if (RET_WAS_ERROR(r)) {
+				free(package);
 				return r;
+			}
 			if (RET_IS_OK(r) && filekeys.count > 0) {
 				if (q - p == 9) { /* filekey */
 					value = filekeys.values[0];
@@ -116,8 +127,10 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 				} else { /* fullfilename */
 					value = calc_dirconcat(global.basedir,
 							filekeys.values[0]);
-					if (FAILEDTOALLOC(value))
+					if (FAILEDTOALLOC(value)) {
+						free(package);
 						return RET_ERROR_OOM;
+					}
 					v = value;
 				}
 				strlist_done(&filekeys);
@@ -144,8 +157,10 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 			char *dummy = NULL;
 			r = target->getsourceandversion(control, package,
 					&value, &dummy);
-			if (RET_WAS_ERROR(r))
+			if (RET_WAS_ERROR(r)) {
+				free(package);
 				return r;
+			}
 			if (RET_IS_OK(r)) {
 				free(dummy);
 				v = value;
@@ -157,8 +172,10 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 			char *dummy = NULL;
 			r = target->getsourceandversion(control, package,
 					&dummy, &value);
-			if (RET_WAS_ERROR(r))
+			if (RET_WAS_ERROR(r)) {
+				free(package);
 				return r;
+			}
 			if (RET_IS_OK(r)) {
 				free(dummy);
 				v = value;
@@ -171,12 +188,16 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 			v = package;
 		} else {
 			char *variable = strndup(p + 1, q - (p + 1));
-			if (FAILEDTOALLOC(variable))
+			if (FAILEDTOALLOC(variable)) {
+				free(package);
 				return RET_ERROR_OOM;
+			}
 			r = chunk_getwholedata(control, variable, &value);
 			free(variable);
-			if (RET_WAS_ERROR(r))
+			if (RET_WAS_ERROR(r)) {
+				free(package);
 				return r;
+			}
 			if (RET_IS_OK(r)) {
 				v = value;
 				while (*v != '\0' && xisspace(*v))
@@ -225,6 +246,7 @@ retvalue listformat_print(const char *listformat, const struct target *target, c
 		}
 		free(value);
 	}
+	free(package);
 	return RET_OK;
 }
 
diff --git a/printlistformat.h b/printlistformat.h
index 6010fee..451b4a7 100644
--- a/printlistformat.h
+++ b/printlistformat.h
@@ -1,6 +1,6 @@
 #ifndef REPREPRO_PRINTLISTFORMAT
 #define REPREPRO_PRINTLISTFORMAT
 
-retvalue listformat_print(const char *, const struct target *, const char *, const char *);
+retvalue listformat_print(const char *, const struct target *, const char *);
 
 #endif
diff --git a/sources.c b/sources.c
index 8db039f..b6fc0e0 100644
--- a/sources.c
+++ b/sources.c
@@ -118,6 +118,20 @@ static retvalue getBasenames(const struct strlist *filelines, /*@out@*/struct st
 	return r;
 }
 
+retvalue sources_getpackage(const char *control, char **package) {
+	retvalue r;
+
+	r = chunk_getvalue(control, "Package", package);
+	if (RET_WAS_ERROR(r))
+		return r;
+	if (r == RET_NOTHING) {
+		fprintf(stderr, "Missing 'Package' field in chunk:'%s'\n",
+				control);
+		return RET_ERROR;
+	}
+	return r;
+}
+
 retvalue sources_getversion(const char *control, char **version) {
 	retvalue r;
 
diff --git a/sources.h b/sources.h
index 3be4c2e..f11c5b4 100644
--- a/sources.h
+++ b/sources.h
@@ -10,6 +10,7 @@
 #endif
 
 /* Functions for the target.h-stuff: */
+get_package sources_getpackage;
 get_version sources_getversion;
 get_installdata sources_getinstalldata;
 get_architecture sources_getarchitecture;
diff --git a/target.c b/target.c
index e74c35b..89ea7da 100644
--- a/target.c
+++ b/target.c
@@ -58,7 +58,7 @@ static char *calc_identifier(const char *codename, component_t component, archit
 }
 
 
-static retvalue target_initialize(/*@dependant@*/struct distribution *distribution, component_t component, architecture_t architecture, packagetype_t packagetype, get_version getversion, get_installdata getinstalldata, get_architecture getarchitecture, get_filekeys getfilekeys, get_checksums getchecksums, get_sourceandversion getsourceandversion, do_reoverride doreoverride, do_retrack doretrack, complete_checksums docomplete, /*@null@*//*@only@*/char *directory, /*@dependent@*/const struct exportmode *exportmode, bool readonly, /*@out@*/struct target **d) {
+static retvalue target_initialize(/*@dependant@*/struct distribution *distribution, component_t component, architecture_t architecture, packagetype_t packagetype, get_package getpackage, get_version getversion, get_installdata getinstalldata, get_architecture getarchitecture, get_filekeys getfilekeys, get_checksums getchecksums, get_sourceandversion getsourceandversion, do_reoverride doreoverride, do_retrack doretrack, complete_checksums docomplete, /*@null@*//*@only@*/char *directory, /*@dependent@*/const struct exportmode *exportmode, bool readonly, /*@out@*/struct target **d) {
 	struct target *t;
 
 	assert(exportmode != NULL);
@@ -85,6 +85,7 @@ static retvalue target_initialize(/*@dependant@*/struct distribution *distributi
 		(void)target_free(t);
 		return RET_ERROR_OOM;
 	}
+	t->getpackage = getpackage;
 	t->getversion = getversion;
 	t->getinstalldata = getinstalldata;
 	t->getarchitecture = getarchitecture;
@@ -115,6 +116,7 @@ static const char *dist_component_name(component_t component, /*@null@*/const ch
 
 retvalue target_initialize_ubinary(struct distribution *d, component_t component, architecture_t architecture, const struct exportmode *exportmode, bool readonly, const char *fakecomponentprefix, struct target **target) {
 	return target_initialize(d, component, architecture, pt_udeb,
+			binaries_getpackage,
 			binaries_getversion,
 			binaries_getinstalldata,
 			binaries_getarchitecture,
@@ -130,6 +132,7 @@ retvalue target_initialize_ubinary(struct distribution *d, component_t component
 }
 retvalue target_initialize_binary(struct distribution *d, component_t component, architecture_t architecture, const struct exportmode *exportmode, bool readonly, const char *fakecomponentprefix, struct target **target) {
 	return target_initialize(d, component, architecture, pt_deb,
+			binaries_getpackage,
 			binaries_getversion,
 			binaries_getinstalldata,
 			binaries_getarchitecture,
@@ -146,6 +149,7 @@ retvalue target_initialize_binary(struct distribution *d, component_t component,
 
 retvalue target_initialize_source(struct distribution *d, component_t component, const struct exportmode *exportmode, bool readonly, const char *fakecomponentprefix, struct target **target) {
 	return target_initialize(d, component, architecture_source, pt_dsc,
+			sources_getpackage,
 			sources_getversion,
 			sources_getinstalldata,
 			sources_getarchitecture,
@@ -363,12 +367,19 @@ retvalue target_removepackage_by_cursor(struct target_cursor *tc, struct logger
 
 static retvalue addpackages(struct target *target, const char *packagename, const char *controlchunk, /*@null@*/const char *oldcontrolchunk, const char *version, /*@null@*/const char *oldversion, const struct strlist *files, /*@only@*//*@null@*/struct strlist *oldfiles, /*@null@*/struct logger *logger, /*@null@*/struct trackingdata *trackingdata, architecture_t architecture, /*@null@*//*@only@*/char *oldsource, /*@null@*//*@only@*/char *oldsversion, /*@null@*/const char *causingrule, /*@null@*/const char *suitefrom) {
 
+	char *key;
 	retvalue result, r;
 	struct table *table = target->packages;
 	enum filetype filetype;
 
 	assert (atom_defined(architecture));
 
+	key = malloc(strlen(packagename) + 1 + strlen(version) + 1);
+	// FIXME: check length
+	strcpy(key, packagename);
+	strcat(key, "|");
+	strcat(key, version);
+
 	if (architecture == architecture_source)
 		filetype = ft_SOURCE;
 	else if (architecture == architecture_all)
@@ -389,10 +400,10 @@ static retvalue addpackages(struct target *target, const char *packagename, cons
 	/* Add package to the distribution's database */
 
 	if (oldcontrolchunk != NULL) {
-		result = table_replacerecord(table, packagename, controlchunk);
+		result = table_replacerecord(table, key, controlchunk);
 
 	} else {
-		result = table_adduniqrecord(table, packagename, controlchunk);
+		result = table_adduniqrecord(table, key, controlchunk);
 	}
 
 	if (RET_WAS_ERROR(result)) {
@@ -426,11 +437,18 @@ retvalue target_addpackage(struct target *target, struct logger *logger, const c
 	struct strlist oldfilekeys, *ofk;
 	char *oldcontrol, *oldsource, *oldsversion;
 	char *oldpversion;
+	char *key;
 	retvalue r;
 
 	assert(target->packages!=NULL);
 
-	r = table_getrecord(target->packages, name, &oldcontrol);
+	key = malloc(strlen(name) + 1 + strlen(version) + 1);
+	// FIXME: check length
+	strcpy(key, name);
+	strcat(key, "|");
+	strcat(key, version);
+
+	r = table_getrecord(target->packages, key, &oldcontrol);
 	if (RET_WAS_ERROR(r))
 		return r;
 	if (r == RET_NOTHING) {
diff --git a/target.h b/target.h
index c979211..7d4a02c 100644
--- a/target.h
+++ b/target.h
@@ -26,6 +26,7 @@
 struct target;
 struct alloverrides;
 
+typedef retvalue get_package(const char *, /*@out@*/char **);
 typedef retvalue get_version(const char *, /*@out@*/char **);
 typedef retvalue get_architecture(const char *, /*@out@*/architecture_t *);
 typedef retvalue get_installdata(const struct target *, const char *, const char *, architecture_t, const char *, /*@out@*/char **, /*@out@*/struct strlist *, /*@out@*/struct checksumsarray *);
@@ -49,6 +50,7 @@ struct target {
 	/* the directory relative to <distdir>/<codename>/ to use */
 	char *relativedirectory;
 	/* functions to use on the packages included */
+	get_package *getpackage;
 	get_version *getversion;
 	/* binary packages might be "all" or the architecture of the target */
 	get_architecture *getarchitecture;
@@ -112,6 +114,27 @@ static inline retvalue target_openiterator(struct target *t, bool readonly, /*@o
 	tc->cursor = c;
 	return RET_OK;
 }
+
+static inline retvalue target_sec_openiterator(struct target *t, bool readonly, /*@out@*/struct target_cursor *tc) {
+	retvalue r, r2;
+	struct cursor *c;
+
+	r = target_initpackagesdb(t, readonly);
+	assert (r != RET_NOTHING);
+	if (RET_WAS_ERROR(r))
+		return r;
+	r = table_sec_newglobalcursor(t->packages, &c);
+	assert (r != RET_NOTHING);
+	if (RET_WAS_ERROR(r)) {
+		r2 = target_closepackagesdb(t);
+		RET_UPDATE(r, r2);
+		return r;
+	}
+	tc->target = t;
+	tc->cursor = c;
+	return RET_OK;
+}
+
 /* wrapper around cursor_nexttemp */
 static inline bool target_nextpackage(struct target_cursor *tc, /*@out@*/const char **packagename_p, /*@out@*/const char **chunk_p) {
 	bool success;

Reply via email to