struct db_rbt_node {
struct rb_node rb_node;
size_t keysize, valuesize;
-
- /*
- * key and value are appended implicitly, "data" is only here as a
- * target for offsetof()
- */
-
- char data[1];
};
/*
static void db_rbt_parse_node(struct db_rbt_node *node,
TDB_DATA *key, TDB_DATA *value)
{
- key->dptr = ((uint8_t *)node) + offsetof(struct db_rbt_node, data);
+ size_t key_offset, value_offset;
+
+ key_offset = DBWRAP_RBT_ALIGN(sizeof(struct db_rbt_node));
+ key->dptr = ((uint8_t *)node) + key_offset;
key->dsize = node->keysize;
- value->dptr = key->dptr + node->keysize;
+
+ value_offset = DBWRAP_RBT_ALIGN(node->keysize);
+ value->dptr = key->dptr + value_offset;
value->dsize = node->valuesize;
}
+static ssize_t db_rbt_reclen(size_t keylen, size_t valuelen)
+{
+ size_t len, tmp;
+
+ len = DBWRAP_RBT_ALIGN(sizeof(struct db_rbt_node));
+
+ tmp = DBWRAP_RBT_ALIGN(keylen);
+ if (tmp < keylen) {
+ goto overflow;
+ }
+
+ len += tmp;
+ if (len < tmp) {
+ goto overflow;
+ }
+
+ len += valuelen;
+ if (len < valuelen) {
+ goto overflow;
+ }
+
+ return len;
+overflow:
+ return -1;
+}
+
static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
{
struct db_rbt_ctx *db_ctx = talloc_get_type_abort(
struct rb_node ** p;
struct rb_node * parent;
+ ssize_t reclen;
TDB_DATA this_key, this_val;
if (rec_priv->node != NULL) {
}
}
- node = (struct db_rbt_node *)talloc_size(db_ctx,
- offsetof(struct db_rbt_node, data) + rec->key.dsize
- + data.dsize);
+ reclen = db_rbt_reclen(rec->key.dsize, data.dsize);
+ if (reclen == -1) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
+ node = talloc_zero_size(db_ctx, reclen);
if (node == NULL) {
return NT_STATUS_NO_MEMORY;
}
*/
}
- ZERO_STRUCT(node->rb_node);
-
node->keysize = rec->key.dsize;
node->valuesize = data.dsize;
return NT_STATUS_OK;
}
+
+static NTSTATUS db_rbt_store_deny(struct db_record *rec, TDB_DATA data, int flag)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static NTSTATUS db_rbt_delete_deny(struct db_record *rec)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
struct db_rbt_search_result {
TDB_DATA key;
TDB_DATA val;
return NT_STATUS_OK;
}
-static int db_rbt_traverse_internal(struct rb_node *n,
+static int db_rbt_traverse_internal(struct db_context *db,
+ struct rb_node *n,
int (*f)(struct db_record *db,
void *private_data),
- void *private_data, uint32_t* count)
+ void *private_data, uint32_t* count,
+ bool rw)
{
- struct db_rbt_node *r;
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
struct db_record rec;
+ struct db_rbt_rec rec_priv;
int ret;
if (n == NULL) {
return 0;
}
- ret = db_rbt_traverse_internal(n->rb_left, f, private_data, count);
+ rb_left = n->rb_left;
+ rb_right = n->rb_right;
+
+ ret = db_rbt_traverse_internal(db, rb_left, f, private_data, count, rw);
if (ret != 0) {
return ret;
}
- r = db_rbt2node(n);
+ rec_priv.node = db_rbt2node(n);
+ /* n might be altered by the callback function */
+ n = NULL;
+
ZERO_STRUCT(rec);
- db_rbt_parse_node(r, &rec.key, &rec.value);
+ rec.db = db;
+ rec.private_data = &rec_priv;
+ if (rw) {
+ rec.store = db_rbt_store;
+ rec.delete_rec = db_rbt_delete;
+ } else {
+ rec.store = db_rbt_store_deny;
+ rec.delete_rec = db_rbt_delete_deny;
+ }
+ db_rbt_parse_node(rec_priv.node, &rec.key, &rec.value);
ret = f(&rec, private_data);
(*count) ++;
return ret;
}
- return db_rbt_traverse_internal(n->rb_right, f, private_data, count);
+ if (rec_priv.node != NULL) {
+ /*
+ * If the current record is still there
+ * we should take the current rb_right.
+ */
+ rb_right = rec_priv.node->rb_node.rb_right;
+ }
+
+ return db_rbt_traverse_internal(db, rb_right, f, private_data, count, rw);
}
static int db_rbt_traverse(struct db_context *db,
db->private_data, struct db_rbt_ctx);
uint32_t count = 0;
- int ret = db_rbt_traverse_internal(ctx->tree.rb_node, f, private_data, &count);
+ int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
+ f, private_data, &count,
+ true /* rw */);
+ if (ret != 0) {
+ return -1;
+ }
+ if (count > INT_MAX) {
+ return -1;
+ }
+ return count;
+}
+
+static int db_rbt_traverse_read(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+ uint32_t count = 0;
+
+ int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
+ f, private_data, &count,
+ false /* rw */);
if (ret != 0) {
return -1;
}
return 0;
}
-static void db_rbt_id(struct db_context *db, const uint8_t **id, size_t *idlen)
+static size_t db_rbt_id(struct db_context *db, uint8_t *id, size_t idlen)
{
- *id = (uint8_t *)db;
- *idlen = sizeof(struct db_context *);
+ if (idlen >= sizeof(struct db_context *)) {
+ memcpy(id, &db, sizeof(struct db_context *));
+ }
+ return sizeof(struct db_context *);
}
struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx)
{
struct db_context *result;
- result = talloc(mem_ctx, struct db_context);
+ result = talloc_zero(mem_ctx, struct db_context);
if (result == NULL) {
return NULL;
}
result->fetch_locked = db_rbt_fetch_locked;
- result->try_fetch_locked = NULL;
result->traverse = db_rbt_traverse;
- result->traverse_read = db_rbt_traverse;
+ result->traverse_read = db_rbt_traverse_read;
result->get_seqnum = db_rbt_get_seqnum;
result->transaction_start = db_rbt_trans_dummy;
result->transaction_commit = db_rbt_trans_dummy;
result->exists = db_rbt_exists;
result->wipe = db_rbt_wipe;
result->parse_record = db_rbt_parse_record;
- result->lock_order = 0;
result->id = db_rbt_id;
- result->stored_callback = NULL;
+ result->name = "dbwrap rbt";
return result;
}