dbwrap_rbt: use talloc_zero_size() instead of a partial ZERO_STRUCT()
[kai/samba-autobuild/.git] / lib / dbwrap / dbwrap_rbt.c
index 2cc52b1da61597ca9d005e0aaa460248733cad3d..37d9649a759b1a67b9f6bbb1d325dabb27b536a1 100644 (file)
@@ -38,13 +38,6 @@ struct db_rbt_rec {
 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];
 };
 
 /*
@@ -83,12 +76,43 @@ static int db_rbt_compare(TDB_DATA a, TDB_DATA b)
 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(
@@ -99,6 +123,7 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
        struct rb_node ** p;
        struct rb_node * parent;
 
+       ssize_t reclen;
        TDB_DATA this_key, this_val;
 
        if (rec_priv->node != NULL) {
@@ -123,10 +148,12 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
                }
        }
 
-       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;
        }
@@ -145,8 +172,6 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
                 */
        }
 
-       ZERO_STRUCT(node->rb_node);
-
        node->keysize = rec->key.dsize;
        node->valuesize = data.dsize;
 
@@ -206,6 +231,17 @@ static NTSTATUS db_rbt_delete(struct db_record *rec)
 
        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;
@@ -346,27 +382,46 @@ static NTSTATUS db_rbt_parse_record(struct db_context *db, TDB_DATA key,
        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) ++;
@@ -374,7 +429,15 @@ static int db_rbt_traverse_internal(struct rb_node *n,
                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,
@@ -386,7 +449,30 @@ 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;
        }
@@ -409,17 +495,19 @@ static int db_rbt_trans_dummy(struct db_context *db)
        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;
@@ -433,9 +521,8 @@ struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx)
        }
 
        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;
@@ -443,9 +530,8 @@ struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx)
        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;
 }