xref: /aosp_15_r20/external/selinux/libsemanage/src/database_join.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /* Copyright (C) 2005 Red Hat, Inc. */
2*2d543d20SAndroid Build Coastguard Worker 
3*2d543d20SAndroid Build Coastguard Worker /* Object: dbase_join_t (Join)
4*2d543d20SAndroid Build Coastguard Worker  * Extends: dbase_llist_t (Linked List)
5*2d543d20SAndroid Build Coastguard Worker  * Implements: dbase_t (Database)
6*2d543d20SAndroid Build Coastguard Worker  */
7*2d543d20SAndroid Build Coastguard Worker 
8*2d543d20SAndroid Build Coastguard Worker struct dbase_join;
9*2d543d20SAndroid Build Coastguard Worker typedef struct dbase_join dbase_t;
10*2d543d20SAndroid Build Coastguard Worker #define DBASE_DEFINED
11*2d543d20SAndroid Build Coastguard Worker 
12*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
13*2d543d20SAndroid Build Coastguard Worker 
14*2d543d20SAndroid Build Coastguard Worker #include "user_internal.h"
15*2d543d20SAndroid Build Coastguard Worker #include "debug.h"
16*2d543d20SAndroid Build Coastguard Worker #include "handle.h"
17*2d543d20SAndroid Build Coastguard Worker #include "database_join.h"
18*2d543d20SAndroid Build Coastguard Worker #include "database_llist.h"
19*2d543d20SAndroid Build Coastguard Worker 
20*2d543d20SAndroid Build Coastguard Worker /* JOIN dbase */
21*2d543d20SAndroid Build Coastguard Worker struct dbase_join {
22*2d543d20SAndroid Build Coastguard Worker 
23*2d543d20SAndroid Build Coastguard Worker 	/* Parent object - must always be
24*2d543d20SAndroid Build Coastguard Worker 	 * the first field - here we are using
25*2d543d20SAndroid Build Coastguard Worker 	 * a linked list to store the records */
26*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_t llist;
27*2d543d20SAndroid Build Coastguard Worker 
28*2d543d20SAndroid Build Coastguard Worker 	/* Backing databases - for each
29*2d543d20SAndroid Build Coastguard Worker 	 * thing being joined  */
30*2d543d20SAndroid Build Coastguard Worker 	dbase_config_t *join1;
31*2d543d20SAndroid Build Coastguard Worker 	dbase_config_t *join2;
32*2d543d20SAndroid Build Coastguard Worker 
33*2d543d20SAndroid Build Coastguard Worker 	/* JOIN extension */
34*2d543d20SAndroid Build Coastguard Worker 	record_join_table_t *rjtable;
35*2d543d20SAndroid Build Coastguard Worker };
36*2d543d20SAndroid Build Coastguard Worker 
dbase_join_cache(semanage_handle_t * handle,dbase_join_t * dbase)37*2d543d20SAndroid Build Coastguard Worker static int dbase_join_cache(semanage_handle_t * handle, dbase_join_t * dbase)
38*2d543d20SAndroid Build Coastguard Worker {
39*2d543d20SAndroid Build Coastguard Worker 
40*2d543d20SAndroid Build Coastguard Worker 	/* Extract all the object tables information */
41*2d543d20SAndroid Build Coastguard Worker 	dbase_t *dbase1 = dbase->join1->dbase;
42*2d543d20SAndroid Build Coastguard Worker 	dbase_t *dbase2 = dbase->join2->dbase;
43*2d543d20SAndroid Build Coastguard Worker 	dbase_table_t *dtable1 = dbase->join1->dtable;
44*2d543d20SAndroid Build Coastguard Worker 	dbase_table_t *dtable2 = dbase->join2->dtable;
45*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist);
46*2d543d20SAndroid Build Coastguard Worker 	record_join_table_t *rjtable = dbase->rjtable;
47*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable1 = dtable1->get_rtable(dbase1);
48*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable2 = dtable2->get_rtable(dbase2);
49*2d543d20SAndroid Build Coastguard Worker 
50*2d543d20SAndroid Build Coastguard Worker 	record_key_t *rkey = NULL;
51*2d543d20SAndroid Build Coastguard Worker 	record_t *record = NULL;
52*2d543d20SAndroid Build Coastguard Worker 	record1_t **records1 = NULL;
53*2d543d20SAndroid Build Coastguard Worker 	record2_t **records2 = NULL;
54*2d543d20SAndroid Build Coastguard Worker 	unsigned int rcount1 = 0, rcount2 = 0, i = 0, j = 0;
55*2d543d20SAndroid Build Coastguard Worker 
56*2d543d20SAndroid Build Coastguard Worker 	/* Already cached */
57*2d543d20SAndroid Build Coastguard Worker 	if (!dbase_llist_needs_resync(handle, &dbase->llist))
58*2d543d20SAndroid Build Coastguard Worker 		return STATUS_SUCCESS;
59*2d543d20SAndroid Build Coastguard Worker 
60*2d543d20SAndroid Build Coastguard Worker 	/* Update cache serial */
61*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_cache_init(&dbase->llist);
62*2d543d20SAndroid Build Coastguard Worker 	if (dbase_llist_set_serial(handle, &dbase->llist) < 0)
63*2d543d20SAndroid Build Coastguard Worker 		goto err;
64*2d543d20SAndroid Build Coastguard Worker 
65*2d543d20SAndroid Build Coastguard Worker 	/* First cache any child dbase, which must
66*2d543d20SAndroid Build Coastguard Worker 	 * be the first thing done when calling dbase
67*2d543d20SAndroid Build Coastguard Worker 	 * functions internally */
68*2d543d20SAndroid Build Coastguard Worker 	if (dtable1->cache(handle, dbase1) < 0)
69*2d543d20SAndroid Build Coastguard Worker 		goto err;
70*2d543d20SAndroid Build Coastguard Worker 	if (dtable2->cache(handle, dbase2) < 0)
71*2d543d20SAndroid Build Coastguard Worker 		goto err;
72*2d543d20SAndroid Build Coastguard Worker 
73*2d543d20SAndroid Build Coastguard Worker 	/* Fetch records */
74*2d543d20SAndroid Build Coastguard Worker 	if (dtable1->list(handle, dbase1, &records1, &rcount1) < 0)
75*2d543d20SAndroid Build Coastguard Worker 		goto err;
76*2d543d20SAndroid Build Coastguard Worker 	if (dtable2->list(handle, dbase2, &records2, &rcount2) < 0)
77*2d543d20SAndroid Build Coastguard Worker 		goto err;
78*2d543d20SAndroid Build Coastguard Worker 
79*2d543d20SAndroid Build Coastguard Worker 	/* Sort for quicker merge later */
80*2d543d20SAndroid Build Coastguard Worker 	if (rcount1 > 0) {
81*2d543d20SAndroid Build Coastguard Worker 		qsort(records1, rcount1, sizeof(record1_t *),
82*2d543d20SAndroid Build Coastguard Worker 		      (int (*)(const void *, const void *))rtable1->compare2_qsort);
83*2d543d20SAndroid Build Coastguard Worker 	}
84*2d543d20SAndroid Build Coastguard Worker 	if (rcount2 > 0) {
85*2d543d20SAndroid Build Coastguard Worker 		qsort(records2, rcount2, sizeof(record2_t *),
86*2d543d20SAndroid Build Coastguard Worker 		      (int (*)(const void *, const void *))rtable2->compare2_qsort);
87*2d543d20SAndroid Build Coastguard Worker 	}
88*2d543d20SAndroid Build Coastguard Worker 
89*2d543d20SAndroid Build Coastguard Worker 	/* Now merge into this dbase */
90*2d543d20SAndroid Build Coastguard Worker 	while (i < rcount1 || j < rcount2) {
91*2d543d20SAndroid Build Coastguard Worker 		int rc;
92*2d543d20SAndroid Build Coastguard Worker 
93*2d543d20SAndroid Build Coastguard Worker 		/* End of one list, or the other */
94*2d543d20SAndroid Build Coastguard Worker 		if (i == rcount1)
95*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
96*2d543d20SAndroid Build Coastguard Worker 		else if (j == rcount2)
97*2d543d20SAndroid Build Coastguard Worker 			rc = 1;
98*2d543d20SAndroid Build Coastguard Worker 
99*2d543d20SAndroid Build Coastguard Worker 		/* Still more records to go, compare them */
100*2d543d20SAndroid Build Coastguard Worker 		else {
101*2d543d20SAndroid Build Coastguard Worker 			if (rtable1->key_extract(handle, records1[i], &rkey) <
102*2d543d20SAndroid Build Coastguard Worker 			    0)
103*2d543d20SAndroid Build Coastguard Worker 				goto err;
104*2d543d20SAndroid Build Coastguard Worker 
105*2d543d20SAndroid Build Coastguard Worker 			rc = rtable2->compare(records2[j], rkey);
106*2d543d20SAndroid Build Coastguard Worker 
107*2d543d20SAndroid Build Coastguard Worker 			rtable->key_free(rkey);
108*2d543d20SAndroid Build Coastguard Worker 			rkey = NULL;
109*2d543d20SAndroid Build Coastguard Worker 		}
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker 		/* Missing record1 data */
112*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0) {
113*2d543d20SAndroid Build Coastguard Worker 			if (rjtable->join(handle, NULL,
114*2d543d20SAndroid Build Coastguard Worker 					  records2[j], &record) < 0)
115*2d543d20SAndroid Build Coastguard Worker 				goto err;
116*2d543d20SAndroid Build Coastguard Worker 			j++;
117*2d543d20SAndroid Build Coastguard Worker 		}
118*2d543d20SAndroid Build Coastguard Worker 
119*2d543d20SAndroid Build Coastguard Worker 		/* Missing record2 data */
120*2d543d20SAndroid Build Coastguard Worker 		else if (rc > 0) {
121*2d543d20SAndroid Build Coastguard Worker 			if (rjtable->join(handle, records1[i],
122*2d543d20SAndroid Build Coastguard Worker 					  NULL, &record) < 0)
123*2d543d20SAndroid Build Coastguard Worker 				goto err;
124*2d543d20SAndroid Build Coastguard Worker 			i++;
125*2d543d20SAndroid Build Coastguard Worker 		}
126*2d543d20SAndroid Build Coastguard Worker 
127*2d543d20SAndroid Build Coastguard Worker 		/* Both records available */
128*2d543d20SAndroid Build Coastguard Worker 		else {
129*2d543d20SAndroid Build Coastguard Worker 			if (rjtable->join(handle, records1[i],
130*2d543d20SAndroid Build Coastguard Worker 					  records2[j], &record) < 0)
131*2d543d20SAndroid Build Coastguard Worker 				goto err;
132*2d543d20SAndroid Build Coastguard Worker 
133*2d543d20SAndroid Build Coastguard Worker 			i++;
134*2d543d20SAndroid Build Coastguard Worker 			j++;
135*2d543d20SAndroid Build Coastguard Worker 		}
136*2d543d20SAndroid Build Coastguard Worker 
137*2d543d20SAndroid Build Coastguard Worker 		/* Add result record to database */
138*2d543d20SAndroid Build Coastguard Worker 		if (dbase_llist_cache_prepend(handle, &dbase->llist, record) <
139*2d543d20SAndroid Build Coastguard Worker 		    0)
140*2d543d20SAndroid Build Coastguard Worker 			goto err;
141*2d543d20SAndroid Build Coastguard Worker 
142*2d543d20SAndroid Build Coastguard Worker 		rtable->free(record);
143*2d543d20SAndroid Build Coastguard Worker 		record = NULL;
144*2d543d20SAndroid Build Coastguard Worker 	}
145*2d543d20SAndroid Build Coastguard Worker 
146*2d543d20SAndroid Build Coastguard Worker 	/* Update cache serial */
147*2d543d20SAndroid Build Coastguard Worker 	if (dbase_llist_set_serial(handle, &dbase->llist) < 0)
148*2d543d20SAndroid Build Coastguard Worker 		goto err;
149*2d543d20SAndroid Build Coastguard Worker 
150*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < rcount1; i++)
151*2d543d20SAndroid Build Coastguard Worker 		rtable1->free(records1[i]);
152*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < rcount2; i++)
153*2d543d20SAndroid Build Coastguard Worker 		rtable2->free(records2[i]);
154*2d543d20SAndroid Build Coastguard Worker 	free(records1);
155*2d543d20SAndroid Build Coastguard Worker 	free(records2);
156*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
157*2d543d20SAndroid Build Coastguard Worker 
158*2d543d20SAndroid Build Coastguard Worker       err:
159*2d543d20SAndroid Build Coastguard Worker 	ERR(handle, "could not cache join database");
160*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < rcount1; i++)
161*2d543d20SAndroid Build Coastguard Worker 		rtable1->free(records1[i]);
162*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < rcount2; i++)
163*2d543d20SAndroid Build Coastguard Worker 		rtable2->free(records2[i]);
164*2d543d20SAndroid Build Coastguard Worker 	free(records1);
165*2d543d20SAndroid Build Coastguard Worker 	free(records2);
166*2d543d20SAndroid Build Coastguard Worker 	rtable->key_free(rkey);
167*2d543d20SAndroid Build Coastguard Worker 	rtable->free(record);
168*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_drop_cache(&dbase->llist);
169*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
170*2d543d20SAndroid Build Coastguard Worker }
171*2d543d20SAndroid Build Coastguard Worker 
172*2d543d20SAndroid Build Coastguard Worker /* Flush database */
dbase_join_flush(semanage_handle_t * handle,dbase_join_t * dbase)173*2d543d20SAndroid Build Coastguard Worker static int dbase_join_flush(semanage_handle_t * handle, dbase_join_t * dbase)
174*2d543d20SAndroid Build Coastguard Worker {
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker 	/* Extract all the object tables information */
177*2d543d20SAndroid Build Coastguard Worker 	dbase_t *dbase1 = dbase->join1->dbase;
178*2d543d20SAndroid Build Coastguard Worker 	dbase_t *dbase2 = dbase->join2->dbase;
179*2d543d20SAndroid Build Coastguard Worker 	dbase_table_t *dtable1 = dbase->join1->dtable;
180*2d543d20SAndroid Build Coastguard Worker 	dbase_table_t *dtable2 = dbase->join2->dtable;
181*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist);
182*2d543d20SAndroid Build Coastguard Worker 	record_join_table_t *rjtable = dbase->rjtable;
183*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable1 = dtable1->get_rtable(dbase1);
184*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable2 = dtable2->get_rtable(dbase2);
185*2d543d20SAndroid Build Coastguard Worker 
186*2d543d20SAndroid Build Coastguard Worker 	cache_entry_t *ptr;
187*2d543d20SAndroid Build Coastguard Worker 	record_key_t *rkey = NULL;
188*2d543d20SAndroid Build Coastguard Worker 	record1_t *record1 = NULL;
189*2d543d20SAndroid Build Coastguard Worker 	record2_t *record2 = NULL;
190*2d543d20SAndroid Build Coastguard Worker 
191*2d543d20SAndroid Build Coastguard Worker 	/* No effect of flush */
192*2d543d20SAndroid Build Coastguard Worker 	if (!dbase_llist_is_modified(&dbase->llist))
193*2d543d20SAndroid Build Coastguard Worker 		return STATUS_SUCCESS;
194*2d543d20SAndroid Build Coastguard Worker 
195*2d543d20SAndroid Build Coastguard Worker 	/* Then clear all records from the cache.
196*2d543d20SAndroid Build Coastguard Worker 	 * This is *not* the same as dropping the cache - it's an explicit
197*2d543d20SAndroid Build Coastguard Worker 	 * request to delete all current records. We need to do
198*2d543d20SAndroid Build Coastguard Worker 	 * this because we don't store delete deltas for the join,
199*2d543d20SAndroid Build Coastguard Worker 	 * so we must re-add all records from scratch */
200*2d543d20SAndroid Build Coastguard Worker 	if (dtable1->clear(handle, dbase1) < 0)
201*2d543d20SAndroid Build Coastguard Worker 		goto err;
202*2d543d20SAndroid Build Coastguard Worker 	if (dtable2->clear(handle, dbase2) < 0)
203*2d543d20SAndroid Build Coastguard Worker 		goto err;
204*2d543d20SAndroid Build Coastguard Worker 
205*2d543d20SAndroid Build Coastguard Worker 	/* For each record, split, and add parts into their corresponding databases */
206*2d543d20SAndroid Build Coastguard Worker 	for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) {
207*2d543d20SAndroid Build Coastguard Worker 
208*2d543d20SAndroid Build Coastguard Worker 		if (rtable->key_extract(handle, ptr->data, &rkey) < 0)
209*2d543d20SAndroid Build Coastguard Worker 			goto err;
210*2d543d20SAndroid Build Coastguard Worker 
211*2d543d20SAndroid Build Coastguard Worker 		if (rjtable->split(handle, ptr->data, &record1, &record2) < 0)
212*2d543d20SAndroid Build Coastguard Worker 			goto err;
213*2d543d20SAndroid Build Coastguard Worker 
214*2d543d20SAndroid Build Coastguard Worker 		if (dtable1->add(handle, dbase1, rkey, record1) < 0)
215*2d543d20SAndroid Build Coastguard Worker 			goto err;
216*2d543d20SAndroid Build Coastguard Worker 
217*2d543d20SAndroid Build Coastguard Worker 		if (dtable2->add(handle, dbase2, rkey, record2) < 0)
218*2d543d20SAndroid Build Coastguard Worker 			goto err;
219*2d543d20SAndroid Build Coastguard Worker 
220*2d543d20SAndroid Build Coastguard Worker 		rtable->key_free(rkey);
221*2d543d20SAndroid Build Coastguard Worker 		rtable1->free(record1);
222*2d543d20SAndroid Build Coastguard Worker 		rtable2->free(record2);
223*2d543d20SAndroid Build Coastguard Worker 		rkey = NULL;
224*2d543d20SAndroid Build Coastguard Worker 		record1 = NULL;
225*2d543d20SAndroid Build Coastguard Worker 		record2 = NULL;
226*2d543d20SAndroid Build Coastguard Worker 	}
227*2d543d20SAndroid Build Coastguard Worker 
228*2d543d20SAndroid Build Coastguard Worker 	/* Note that this function does not flush the child databases, it
229*2d543d20SAndroid Build Coastguard Worker 	 * leaves that decision up to higher-level code */
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_set_modified(&dbase->llist, 0);
232*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
233*2d543d20SAndroid Build Coastguard Worker 
234*2d543d20SAndroid Build Coastguard Worker       err:
235*2d543d20SAndroid Build Coastguard Worker 	ERR(handle, "could not flush join database");
236*2d543d20SAndroid Build Coastguard Worker 	rtable->key_free(rkey);
237*2d543d20SAndroid Build Coastguard Worker 	rtable1->free(record1);
238*2d543d20SAndroid Build Coastguard Worker 	rtable2->free(record2);
239*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
240*2d543d20SAndroid Build Coastguard Worker }
241*2d543d20SAndroid Build Coastguard Worker 
dbase_join_init(semanage_handle_t * handle,record_table_t * rtable,record_join_table_t * rjtable,dbase_config_t * join1,dbase_config_t * join2,dbase_t ** dbase)242*2d543d20SAndroid Build Coastguard Worker int dbase_join_init(semanage_handle_t * handle,
243*2d543d20SAndroid Build Coastguard Worker 		    record_table_t * rtable,
244*2d543d20SAndroid Build Coastguard Worker 		    record_join_table_t * rjtable,
245*2d543d20SAndroid Build Coastguard Worker 		    dbase_config_t * join1,
246*2d543d20SAndroid Build Coastguard Worker 		    dbase_config_t * join2, dbase_t ** dbase)
247*2d543d20SAndroid Build Coastguard Worker {
248*2d543d20SAndroid Build Coastguard Worker 
249*2d543d20SAndroid Build Coastguard Worker 	dbase_join_t *tmp_dbase = malloc(sizeof(dbase_join_t));
250*2d543d20SAndroid Build Coastguard Worker 
251*2d543d20SAndroid Build Coastguard Worker 	if (!tmp_dbase)
252*2d543d20SAndroid Build Coastguard Worker 		goto omem;
253*2d543d20SAndroid Build Coastguard Worker 
254*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_JOIN_DTABLE);
255*2d543d20SAndroid Build Coastguard Worker 
256*2d543d20SAndroid Build Coastguard Worker 	tmp_dbase->rjtable = rjtable;
257*2d543d20SAndroid Build Coastguard Worker 	tmp_dbase->join1 = join1;
258*2d543d20SAndroid Build Coastguard Worker 	tmp_dbase->join2 = join2;
259*2d543d20SAndroid Build Coastguard Worker 
260*2d543d20SAndroid Build Coastguard Worker 	*dbase = tmp_dbase;
261*2d543d20SAndroid Build Coastguard Worker 
262*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
263*2d543d20SAndroid Build Coastguard Worker 
264*2d543d20SAndroid Build Coastguard Worker       omem:
265*2d543d20SAndroid Build Coastguard Worker 	ERR(handle, "out of memory, could not initialize join database");
266*2d543d20SAndroid Build Coastguard Worker 	free(tmp_dbase);
267*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
268*2d543d20SAndroid Build Coastguard Worker }
269*2d543d20SAndroid Build Coastguard Worker 
270*2d543d20SAndroid Build Coastguard Worker /* Release dbase resources */
dbase_join_release(dbase_join_t * dbase)271*2d543d20SAndroid Build Coastguard Worker void dbase_join_release(dbase_join_t * dbase)
272*2d543d20SAndroid Build Coastguard Worker {
273*2d543d20SAndroid Build Coastguard Worker 
274*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_drop_cache(&dbase->llist);
275*2d543d20SAndroid Build Coastguard Worker 	free(dbase);
276*2d543d20SAndroid Build Coastguard Worker }
277*2d543d20SAndroid Build Coastguard Worker 
278*2d543d20SAndroid Build Coastguard Worker /* JOIN dbase - method table implementation */
279*2d543d20SAndroid Build Coastguard Worker dbase_table_t SEMANAGE_JOIN_DTABLE = {
280*2d543d20SAndroid Build Coastguard Worker 
281*2d543d20SAndroid Build Coastguard Worker 	/* Cache/Transactions */
282*2d543d20SAndroid Build Coastguard Worker 	.cache = dbase_join_cache,
283*2d543d20SAndroid Build Coastguard Worker 	.drop_cache = (void *)dbase_llist_drop_cache,
284*2d543d20SAndroid Build Coastguard Worker 	.flush = dbase_join_flush,
285*2d543d20SAndroid Build Coastguard Worker 	.is_modified = (void *)dbase_llist_is_modified,
286*2d543d20SAndroid Build Coastguard Worker 
287*2d543d20SAndroid Build Coastguard Worker 	/* Database API */
288*2d543d20SAndroid Build Coastguard Worker 	.iterate = (void *)dbase_llist_iterate,
289*2d543d20SAndroid Build Coastguard Worker 	.exists = (void *)dbase_llist_exists,
290*2d543d20SAndroid Build Coastguard Worker 	.list = (void *)dbase_llist_list,
291*2d543d20SAndroid Build Coastguard Worker 	.add = (void *)dbase_llist_add,
292*2d543d20SAndroid Build Coastguard Worker 	.set = (void *)dbase_llist_set,
293*2d543d20SAndroid Build Coastguard Worker 	.del = (void *)dbase_llist_del,
294*2d543d20SAndroid Build Coastguard Worker 	.clear = (void *)dbase_llist_clear,
295*2d543d20SAndroid Build Coastguard Worker 	.modify = (void *)dbase_llist_modify,
296*2d543d20SAndroid Build Coastguard Worker 	.query = (void *)dbase_llist_query,
297*2d543d20SAndroid Build Coastguard Worker 	.count = (void *)dbase_llist_count,
298*2d543d20SAndroid Build Coastguard Worker 
299*2d543d20SAndroid Build Coastguard Worker 	/* Polymorphism */
300*2d543d20SAndroid Build Coastguard Worker 	.get_rtable = (void *)dbase_llist_get_rtable
301*2d543d20SAndroid Build Coastguard Worker };
302