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 key = NULL;
158 dbase->modified = 1;
159 return STATUS_SUCCESS;
160
161 err:
162 ERR(handle, "could not add record to the database");
163 return STATUS_ERR;
164 }
165
dbase_llist_set(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,const record_t * data)166 int dbase_llist_set(semanage_handle_t * handle,
167 dbase_llist_t * dbase,
168 const record_key_t * key, const record_t * data)
169 {
170
171 cache_entry_t *entry;
172 int status;
173
174 status = dbase_llist_cache_locate(handle, dbase, key, &entry);
175 if (status < 0)
176 goto err;
177 if (status == STATUS_NODATA) {
178 ERR(handle, "record not found in the database");
179 goto err;
180 } else {
181 dbase->rtable->free(entry->data);
182 if (dbase->rtable->clone(handle, data, &entry->data) < 0)
183 goto err;
184 }
185
186 dbase->modified = 1;
187 return STATUS_SUCCESS;
188
189 err:
190 ERR(handle, "could not set record value");
191 return STATUS_ERR;
192 }
193
dbase_llist_modify(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,const record_t * data)194 int dbase_llist_modify(semanage_handle_t * handle,
195 dbase_llist_t * dbase,
196 const record_key_t * key, const record_t * data)
197 {
198
199 cache_entry_t *entry;
200 int status;
201
202 status = dbase_llist_cache_locate(handle, dbase, key, &entry);
203 if (status < 0)
204 goto err;
205 if (status == STATUS_NODATA) {
206 if (dbase_llist_cache_prepend(handle, dbase, data) < 0)
207 goto err;
208 } else {
209 dbase->rtable->free(entry->data);
210 if (dbase->rtable->clone(handle, data, &entry->data) < 0)
211 goto err;
212 }
213
214 dbase->modified = 1;
215 return STATUS_SUCCESS;
216
217 err:
218 ERR(handle, "could not modify record value");
219 return STATUS_ERR;
220 }
221
dbase_llist_count(semanage_handle_t * handle,dbase_llist_t * dbase,unsigned int * response)222 hidden int dbase_llist_count(semanage_handle_t * handle __attribute__ ((unused)),
223 dbase_llist_t * dbase, unsigned int *response)
224 {
225
226 *response = dbase->cache_sz;
227 handle = NULL;
228 return STATUS_SUCCESS;
229 }
230
dbase_llist_query(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key,record_t ** response)231 int dbase_llist_query(semanage_handle_t * handle,
232 dbase_llist_t * dbase,
233 const record_key_t * key, record_t ** response)
234 {
235
236 cache_entry_t *entry;
237 int status;
238
239 status = dbase_llist_cache_locate(handle, dbase, key, &entry);
240 if (status < 0 || status == STATUS_NODATA)
241 goto err;
242
243 if (dbase->rtable->clone(handle, entry->data, response) < 0)
244 goto err;
245
246 return STATUS_SUCCESS;
247
248 err:
249 ERR(handle, "could not query record value");
250 return STATUS_ERR;
251 }
252
dbase_llist_iterate(semanage_handle_t * handle,dbase_llist_t * dbase,int (* fn)(const record_t * record,void * fn_arg),void * arg)253 int dbase_llist_iterate(semanage_handle_t * handle,
254 dbase_llist_t * dbase,
255 int (*fn) (const record_t * record,
256 void *fn_arg), void *arg)
257 {
258
259 int rc;
260 cache_entry_t *ptr;
261
262 for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
263
264 rc = fn(ptr->data, arg);
265 if (rc < 0)
266 goto err;
267
268 else if (rc > 1)
269 break;
270 }
271
272 return STATUS_SUCCESS;
273
274 err:
275 ERR(handle, "could not iterate over records");
276 return STATUS_ERR;
277 }
278
dbase_llist_del(semanage_handle_t * handle,dbase_llist_t * dbase,const record_key_t * key)279 int dbase_llist_del(semanage_handle_t * handle __attribute__ ((unused)),
280 dbase_llist_t * dbase, const record_key_t * key)
281 {
282
283 cache_entry_t *ptr, *prev = NULL;
284
285 for (ptr = dbase->cache; ptr != NULL; ptr = ptr->next) {
286 if (!dbase->rtable->compare(ptr->data, key)) {
287 if (prev != NULL)
288 prev->next = ptr->next;
289 else
290 dbase->cache = ptr->next;
291
292 if (ptr->next != NULL)
293 ptr->next->prev = ptr->prev;
294 else
295 dbase->cache_tail = ptr->prev;
296
297 dbase->rtable->free(ptr->data);
298 dbase->cache_sz--;
299 free(ptr);
300 dbase->modified = 1;
301 return STATUS_SUCCESS;
302 } else
303 prev = ptr;
304 }
305
306 handle = NULL;
307 return STATUS_SUCCESS;
308 }
309
dbase_llist_clear(semanage_handle_t * handle,dbase_llist_t * dbase)310 int dbase_llist_clear(semanage_handle_t * handle, dbase_llist_t * dbase)
311 {
312
313 int old_serial = dbase->cache_serial;
314
315 if (dbase_llist_set_serial(handle, dbase) < 0) {
316 ERR(handle, "could not set serial of cleared dbase");
317 return STATUS_ERR;
318 }
319
320 if (old_serial >= 0) {
321 cache_entry_t *prev, *ptr = dbase->cache;
322 while (ptr != NULL) {
323 prev = ptr;
324 ptr = ptr->next;
325 dbase->rtable->free(prev->data);
326 free(prev);
327 }
328 }
329
330 dbase->cache = NULL;
331 dbase->cache_tail = NULL;
332 dbase->cache_sz = 0;
333 dbase->modified = 1;
334 return STATUS_SUCCESS;
335 }
336
dbase_llist_list(semanage_handle_t * handle,dbase_llist_t * dbase,record_t *** records,unsigned int * count)337 int dbase_llist_list(semanage_handle_t * handle,
338 dbase_llist_t * dbase,
339 record_t *** records, unsigned int *count)
340 {
341
342 cache_entry_t *ptr;
343 record_t **tmp_records = NULL;
344 unsigned int tmp_count;
345 int i = 0;
346
347 tmp_count = dbase->cache_sz;
348 if (tmp_count > 0) {
349 tmp_records = (record_t **)
350 calloc(tmp_count, sizeof(record_t *));
351
352 if (tmp_records == NULL)
353 goto omem;
354
355 for (ptr = dbase->cache_tail; ptr != NULL; ptr = ptr->prev) {
356 if (dbase->rtable->clone(handle,
357 ptr->data,
358 &tmp_records[i]) < 0)
359 goto err;
360 i++;
361 }
362 }
363
364 *records = tmp_records;
365 *count = tmp_count;
366 return STATUS_SUCCESS;
367
368 omem:
369 ERR(handle, "out of memory");
370
371 err:
372 if (tmp_records) {
373 for (; i >= 0; i--)
374 dbase->rtable->free(tmp_records[i]);
375 free(tmp_records);
376 }
377 ERR(handle, "could not allocate record array");
378 return STATUS_ERR;
379 }
380