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