• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2005 Red Hat, Inc. */
2 
3 /* Object: dbase_llist_t (Linked List)
4  * Partially Implements: dbase_t (Database)
5  */
6 
7 struct dbase_llist;
8 typedef struct dbase_llist dbase_t;
9 #define DBASE_DEFINED
10 
11 #include <stdlib.h>
12 #include "debug.h"
13 #include "handle.h"
14 #include "database_llist.h"
15 
dbase_llist_needs_resync(semanage_handle_t * handle,dbase_llist_t * dbase)16 int dbase_llist_needs_resync(semanage_handle_t * handle, dbase_llist_t * dbase)
17 {
18 
19 	int cache_serial;
20 
21 	if (dbase->cache_serial < 0)
22 		return 1;
23 
24 	cache_serial = handle->funcs->get_serial(handle);
25 	if (cache_serial < 0)
26 		return 1;
27 
28 	if (cache_serial != dbase->cache_serial) {
29 		dbase_llist_drop_cache(dbase);
30 		dbase->cache_serial = -1;
31 		return 1;
32 	}
33 	return 0;
34 }
35 
36 /* Helper for adding records to the cache */
dbase_llist_cache_prepend(semanage_handle_t * handle,dbase_llist_t * dbase,const record_t * data)37 int dbase_llist_cache_prepend(semanage_handle_t * handle,
38 			      dbase_llist_t * dbase, const record_t * data)
39 {
40 
41 	/* Initialize */
42 	cache_entry_t *entry = (cache_entry_t *) malloc(sizeof(cache_entry_t));
43 	if (entry == NULL)
44 		goto omem;
45 
46 	if (dbase->rtable->clone(handle, data, &entry->data) < 0)
47 		goto err;
48 
49 	entry->prev = NULL;
50 	entry->next = dbase->cache;
51 
52 	/* Link */
53 	if (dbase->cache != NULL)
54 		dbase->cache->prev = entry;
55 	if (dbase->cache_tail == NULL)
56 		dbase->cache_tail = entry;
57 	dbase->cache = entry;
58 	dbase->cache_sz++;
59 	return STATUS_SUCCESS;
60 
61       omem:
62 	ERR(handle, "out of memory");
63 
64       err:
65 	ERR(handle, "could not cache record");
66 	free(entry);
67 	return STATUS_ERR;
68 }
69 
dbase_llist_drop_cache(dbase_llist_t * dbase)70 void dbase_llist_drop_cache(dbase_llist_t * dbase)
71 {
72 
73 	if (dbase->cache_serial < 0)
74 		return;
75 
76 	cache_entry_t *prev, *ptr = dbase->cache;
77 	while (ptr != NULL) {
78 		prev = ptr;
79 		ptr = ptr->next;
80 		dbase->rtable->free(prev->data);
81 		free(prev);
82 	}
83 
84 	dbase->cache_serial = -1;
85 	dbase->modified = 0;
86 }
87 
dbase_llist_set_serial(semanage_handle_t * handle,dbase_llist_t * dbase)88 int dbase_llist_set_serial(semanage_handle_t * handle, dbase_llist_t * dbase)
89 {
90 
91 	int cache_serial = handle->funcs->get_serial(handle);
92 	if (cache_serial < 0) {
93 		ERR(handle, "could not update cache serial");
94 		return STATUS_ERR;
95 	}
96 
97 	dbase->cache_serial = cache_serial;
98 	return STATUS_SUCCESS;
99 }
100 
101 /* Helper for finding records in the cache */
dbase_llist_cache_locate(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,cache_entry_t ** entry)102 static int dbase_llist_cache_locate(semanage_handle_t * handle,
103 				    dbase_llist_t * dbase,
104 				    const record_key_t * key,
105 				    cache_entry_t ** entry)
106 {
107 
108 	cache_entry_t *ptr;
109 
110 	/* Implemented in parent */
111 	if (dbase->dtable->cache(handle, dbase) < 0)
112 		goto err;
113 
114 	for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
115 		if (!dbase->rtable->compare(ptr->data, key)) {
116 			*entry = ptr;
117 			return STATUS_SUCCESS;
118 		}
119 	}
120 
121 	return STATUS_NODATA;
122 
123       err:
124 	ERR(handle, "could not complete cache lookup");
125 	return STATUS_ERR;
126 }
127 
dbase_llist_exists(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,int * response)128 int dbase_llist_exists(semanage_handle_t * handle,
129 		       dbase_llist_t * dbase,
130 		       const record_key_t * key, int *response)
131 {
132 
133 	cache_entry_t *entry;
134 	int status;
135 
136 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
137 	if (status < 0)
138 		goto err;
139 
140 	*response = (status != STATUS_NODATA);
141 	return STATUS_SUCCESS;
142 
143       err:
144 	ERR(handle, "could not check if record exists");
145 	return STATUS_ERR;
146 }
147 
dbase_llist_add(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,const record_t * data)148 int dbase_llist_add(semanage_handle_t * handle,
149 		    dbase_llist_t * dbase,
150 		    const record_key_t * key __attribute__ ((unused)),
151 			 const record_t * data)
152 {
153 
154 	if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
155 		goto err;
156 
157 	dbase->modified = 1;
158 	return STATUS_SUCCESS;
159 
160       err:
161 	ERR(handle, "could not add record to the database");
162 	return STATUS_ERR;
163 }
164 
dbase_llist_set(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,const record_t * data)165 int dbase_llist_set(semanage_handle_t * handle,
166 		    dbase_llist_t * dbase,
167 		    const record_key_t * key, const record_t * data)
168 {
169 
170 	cache_entry_t *entry;
171 	int status;
172 
173 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
174 	if (status < 0)
175 		goto err;
176 	if (status == STATUS_NODATA) {
177 		ERR(handle, "record not found in the database");
178 		goto err;
179 	} else {
180 		dbase->rtable->free(entry->data);
181 		if (dbase->rtable->clone(handle, data, &entry->data) < 0)
182 			goto err;
183 	}
184 
185 	dbase->modified = 1;
186 	return STATUS_SUCCESS;
187 
188       err:
189 	ERR(handle, "could not set record value");
190 	return STATUS_ERR;
191 }
192 
dbase_llist_modify(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,const record_t * data)193 int dbase_llist_modify(semanage_handle_t * handle,
194 		       dbase_llist_t * dbase,
195 		       const record_key_t * key, const record_t * data)
196 {
197 
198 	cache_entry_t *entry;
199 	int status;
200 
201 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
202 	if (status < 0)
203 		goto err;
204 	if (status == STATUS_NODATA) {
205 		if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
206 			goto err;
207 	} else {
208 		dbase->rtable->free(entry->data);
209 		if (dbase->rtable->clone(handle, data, &entry->data) < 0)
210 			goto err;
211 	}
212 
213 	dbase->modified = 1;
214 	return STATUS_SUCCESS;
215 
216       err:
217 	ERR(handle, "could not modify record value");
218 	return STATUS_ERR;
219 }
220 
dbase_llist_count(semanage_handle_t * handle,dbase_llist_t * dbase,unsigned int * response)221 hidden int dbase_llist_count(semanage_handle_t * handle __attribute__ ((unused)),
222 			     dbase_llist_t * dbase, unsigned int *response)
223 {
224 
225 	*response = dbase->cache_sz;
226 	return STATUS_SUCCESS;
227 }
228 
dbase_llist_query(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,record_t ** response)229 int dbase_llist_query(semanage_handle_t * handle,
230 		      dbase_llist_t * dbase,
231 		      const record_key_t * key, record_t ** response)
232 {
233 
234 	cache_entry_t *entry;
235 	int status;
236 
237 	status = dbase_llist_cache_locate(handle, dbase, key, &entry);
238 	if (status < 0 || status == STATUS_NODATA)
239 		goto err;
240 
241 	if (dbase->rtable->clone(handle, entry->data, response) < 0)
242 		goto err;
243 
244 	return STATUS_SUCCESS;
245 
246       err:
247 	ERR(handle, "could not query record value");
248 	return STATUS_ERR;
249 }
250 
dbase_llist_iterate(semanage_handle_t * handle,dbase_llist_t * dbase,int (* fn)(const record_t * record,void * fn_arg),void * arg)251 int dbase_llist_iterate(semanage_handle_t * handle,
252 			dbase_llist_t * dbase,
253 			int (*fn) (const record_t * record,
254 				   void *fn_arg), void *arg)
255 {
256 
257 	int rc;
258 	cache_entry_t *ptr;
259 
260 	for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
261 
262 		rc = fn(ptr->data, arg);
263 		if (rc < 0)
264 			goto err;
265 
266 		else if (rc > 0)
267 			break;
268 	}
269 
270 	return STATUS_SUCCESS;
271 
272       err:
273 	ERR(handle, "could not iterate over records");
274 	return STATUS_ERR;
275 }
276 
dbase_llist_del(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key)277 int dbase_llist_del(semanage_handle_t * handle __attribute__ ((unused)),
278 		    dbase_llist_t * dbase, const record_key_t * key)
279 {
280 
281 	cache_entry_t *ptr, *prev = NULL;
282 
283 	for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
284 		if (!dbase->rtable->compare(ptr->data, key)) {
285 			if (prev != NULL)
286 				prev->next = ptr->next;
287 			else
288 				dbase->cache = ptr->next;
289 
290 			if (ptr->next != NULL)
291 				ptr->next->prev = ptr->prev;
292 			else
293 				dbase->cache_tail = ptr->prev;
294 
295 			dbase->rtable->free(ptr->data);
296 			dbase->cache_sz--;
297 			free(ptr);
298 			dbase->modified = 1;
299 			return STATUS_SUCCESS;
300 		} else
301 			prev = ptr;
302 	}
303 
304 	return STATUS_SUCCESS;
305 }
306 
dbase_llist_clear(semanage_handle_t * handle,dbase_llist_t * dbase)307 int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase)
308 {
309 
310 	int old_serial = dbase->cache_serial;
311 
312 	if (dbase_llist_set_serial(handle, dbase) < 0) {
313 		ERR(handle, "could not set serial of cleared dbase");
314 		return STATUS_ERR;
315 	}
316 
317 	if (old_serial >= 0) {
318 		cache_entry_t *prev, *ptr = dbase->cache;
319 		while (ptr != NULL) {
320 			prev = ptr;
321 			ptr = ptr->next;
322 			dbase->rtable->free(prev->data);
323 			free(prev);
324 		}
325 	}
326 
327 	dbase->cache = NULL;
328 	dbase->cache_tail = NULL;
329 	dbase->cache_sz = 0;
330 	dbase->modified = 1;
331 	return STATUS_SUCCESS;
332 }
333 
dbase_llist_list(semanage_handle_t * handle,dbase_llist_t * dbase,record_t *** records,unsigned int * count)334 int dbase_llist_list(semanage_handle_t * handle,
335 		     dbase_llist_t * dbase,
336 		     record_t *** records, unsigned int *count)
337 {
338 
339 	cache_entry_t *ptr;
340 	record_t **tmp_records = NULL;
341 	unsigned int tmp_count;
342 	int i = 0;
343 
344 	tmp_count = dbase->cache_sz;
345 	if (tmp_count > 0) {
346 		tmp_records = (record_t **)
347 		    calloc(tmp_count, sizeof(record_t *));
348 
349 		if (tmp_records == NULL)
350 			goto omem;
351 
352 		for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
353 			if (dbase->rtable->clone(handle,
354 						 ptr->data,
355 						 &tmp_records[i]) < 0)
356 				goto err;
357 			i++;
358 		}
359 	}
360 
361 	*records = tmp_records;
362 	*count = tmp_count;
363 	return STATUS_SUCCESS;
364 
365       omem:
366 	ERR(handle, "out of memory");
367 
368       err:
369 	if (tmp_records) {
370 		for (; i >= 0; i--)
371 			dbase->rtable->free(tmp_records[i]);
372 		free(tmp_records);
373 	}
374 	ERR(handle, "could not allocate record array");
375 	return STATUS_ERR;
376 }
377