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 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 */ 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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