/* * UCW Library -- Configuration files: journaling * * (c) 2001--2006 Robert Spalek * (c) 2003--2012 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. */ #include #include #include #include #include #include struct old_pools { struct old_pools *prev; struct mempool *pool; }; // link-list of older cf_pool's struct cf_journal_item { struct cf_journal_item *prev; byte *ptr; uint len; byte copy[0]; }; void cf_set_journalling(int enable) { struct cf_context *cc = cf_get_context(); ASSERT(!cc->journal); cc->enable_journal = enable; } void cf_journal_block(void *ptr, uint len) { struct cf_context *cc = cf_get_context(); if (!cc->enable_journal) return; struct cf_journal_item *ji = cf_malloc(sizeof(struct cf_journal_item) + len); ji->prev = cc->journal; ji->ptr = ptr; ji->len = len; memcpy(ji->copy, ptr, len); cc->journal = ji; } void cf_journal_swap(void) // swaps the contents of the memory and the journal, and reverses the list { struct cf_context *cc = cf_get_context(); struct cf_journal_item *curr, *prev, *next; for (next=NULL, curr=cc->journal; curr; next=curr, curr=prev) { prev = curr->prev; curr->prev = next; for (uint i=0; ilen; i++) { byte x = curr->copy[i]; curr->copy[i] = curr->ptr[i]; curr->ptr[i] = x; } } cc->journal = next; } struct cf_journal_item * cf_journal_new_transaction(uint new_pool) { struct cf_context *cc = cf_get_context(); if (new_pool) cc->pool = mp_new(1<<10); struct cf_journal_item *oldj = cc->journal; cc->journal = NULL; return oldj; } void cf_journal_commit_transaction(uint new_pool, struct cf_journal_item *oldj) { struct cf_context *cc = cf_get_context(); if (new_pool) { struct old_pools *p = cf_malloc(sizeof(struct old_pools)); p->prev = cc->pools; p->pool = cc->pool; cc->pools = p; } if (oldj) { struct cf_journal_item **j = &cc->journal; while (*j) j = &(*j)->prev; *j = oldj; } } void cf_journal_rollback_transaction(uint new_pool, struct cf_journal_item *oldj) { struct cf_context *cc = cf_get_context(); if (!cc->enable_journal) return; cf_journal_swap(); cc->journal = oldj; if (new_pool) { mp_delete(cc->pool); cc->pool = cc->pools ? cc->pools->pool : NULL; } } void cf_journal_delete(void) { struct cf_context *cc = cf_get_context(); for (struct old_pools *p=cc->pools; p; p=cc->pools) { cc->pools = p->prev; mp_delete(p->pool); } }