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 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 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 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 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 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 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 > 1) 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 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 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 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