ldb_tdb: Ensure we can not commit an index that is corrupt due to partial re-index
[metze/samba/wip.git] / lib / ldb / ldb_tdb / ldb_tdb.c
index 9a2b47b87c4a2970b4f705ea92ca244b48d12861..20796f2162dd2180721f8bc5a31053ddd2f52f88 100644 (file)
@@ -410,6 +410,10 @@ static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn)
                ret = ltdb_cache_reload(module);
        }
 
+       if (ret != LDB_SUCCESS) {
+               ltdb->reindex_failed = true;
+       }
+
        return ret;
 }
 
@@ -1443,9 +1447,17 @@ static int ltdb_start_trans(struct ldb_module *module)
 
        ltdb_index_transaction_start(module);
 
+       ltdb->reindex_failed = false;
+
        return LDB_SUCCESS;
 }
 
+/*
+ * Forward declaration to allow prepare_commit to in fact abort the
+ * transaction
+ */
+static int ltdb_del_trans(struct ldb_module *module);
+
 static int ltdb_prepare_commit(struct ldb_module *module)
 {
        int ret;
@@ -1456,6 +1468,24 @@ static int ltdb_prepare_commit(struct ldb_module *module)
                return LDB_SUCCESS;
        }
 
+       /*
+        * Check if the last re-index failed.
+        *
+        * This can happen if for example a duplicate value was marked
+        * unique.  We must not write a partial re-index into the DB.
+        */
+       if (ltdb->reindex_failed) {
+               /*
+                * We must instead abort the transaction so we get the
+                * old values and old index back
+                */
+               ltdb_del_trans(module);
+               ldb_set_errstring(ldb_module_get_ctx(module),
+                                 "Failure during re-index, so "
+                                 "transaction must be aborted.");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
        ret = ltdb_index_transaction_commit(module);
        if (ret != LDB_SUCCESS) {
                ltdb->kv_ops->abort_write(ltdb);
@@ -1799,11 +1829,12 @@ static const char * ltdb_tdb_name(struct ltdb_private *ltdb)
 
 static bool ltdb_tdb_changed(struct ltdb_private *ltdb)
 {
-       bool ret = (tdb_get_seqnum(ltdb->tdb) != ltdb->tdb_seqnum);
+       int seq = tdb_get_seqnum(ltdb->tdb);
+       bool has_changed = (seq != ltdb->tdb_seqnum);
 
-       ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb);
+       ltdb->tdb_seqnum = seq;
 
-       return ret;
+       return has_changed;
 }
 
 static const struct kv_db_ops key_value_ops = {
@@ -2058,9 +2089,9 @@ int init_store(struct ltdb_private *ltdb,
 /*
   connect to the database
 */
-static int ltdb_connect(struct ldb_context *ldb, const char *url,
-                       unsigned int flags, const char *options[],
-                       struct ldb_module **_module)
+int ltdb_connect(struct ldb_context *ldb, const char *url,
+                unsigned int flags, const char *options[],
+                struct ldb_module **_module)
 {
        const char *path;
        int tdb_flags, open_flags;
@@ -2146,9 +2177,3 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url,
 
        return init_store(ltdb, "ldb_tdb backend", ldb, options, _module);
 }
-
-int ldb_tdb_init(const char *version)
-{
-       LDB_MODULE_CHECK_VERSION(version);
-       return ldb_register_backend("tdb", ltdb_connect, false);
-}