*/
#include "dsdb/samdb/ldb_modules/partition.h"
+#include "lib/ldb-samba/ldb_wrap.h"
#include "system/filesys.h"
#define LDB_METADATA_SEQ_NUM "SEQ_NUM"
TDB_DATA tdb_key, tdb_data;
char *value_str;
TALLOC_CTX *tmp_ctx;
+ int error = 0;
data = talloc_get_type_abort(ldb_module_get_private(module),
struct partition_private_data);
tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
tdb_key.dsize = strlen(key);
- tdb_data = tdb_fetch_compat(tdb, tdb_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
if (!tdb_data.dptr) {
if (tdb_error(tdb) == TDB_ERR_NOEXIST) {
*value = default_value;
return LDB_SUCCESS;
} else {
return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
- tdb_errorstr_compat(tdb));
+ tdb_errorstr(tdb));
}
}
return ldb_module_oom(module);
}
- *value = strtoull(value_str, NULL, 10);
+ *value = strtoull_err(value_str, NULL, 10, &error);
+ if (error != 0) {
+ return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+ "partition_metadata: converision failed");
+ }
SAFE_FREE(tdb_data.dptr);
talloc_free(tmp_ctx);
}
if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) {
+ int ret;
+ char *error_string = talloc_asprintf(tmp_ctx, "%s: tdb_store of key %s failed: %s",
+ tdb_name(tdb), key, tdb_errorstr(tdb));
+ ret = ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+ error_string);
talloc_free(tmp_ctx);
- return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
- tdb_errorstr_compat(tdb));
+ return ret;
}
talloc_free(tmp_ctx);
return LDB_SUCCESS;
}
+int partition_metadata_inc_schema_sequence(struct ldb_module *module)
+{
+ struct partition_private_data *data;
+ int ret;
+ uint64_t value = 0;
+
+ data = talloc_get_type_abort(ldb_module_get_private(module),
+ struct partition_private_data);
+ if (!data || !data->metadata) {
+ return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+ "partition_metadata: metadata not initialized");
+ }
+
+ if (data->metadata->in_transaction == 0) {
+ return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+ "partition_metadata: increment sequence number without transaction");
+ }
+ ret = partition_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ value++;
+ ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, false);
+ if (ret == LDB_ERR_OPERATIONS_ERROR) {
+ /* Modify failed, let's try the add */
+ ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, true);
+ }
+ return ret;
+}
+
+
/*
* Open sam.ldb.d/metadata.tdb.
TALLOC_CTX *tmp_ctx;
struct partition_private_data *data;
struct loadparm_context *lp_ctx;
- const char *sam_name;
char *filename, *dirname;
- int open_flags;
+ int open_flags, tdb_flags, ldb_flags;
struct stat statbuf;
data = talloc_get_type_abort(ldb_module_get_private(module),
return ldb_module_oom(module);
}
- sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url");
- if (strncmp("tdb://", sam_name, 6) == 0) {
- sam_name += 6;
- }
- if (!sam_name) {
- talloc_free(tmp_ctx);
- return ldb_operr(ldb);
- }
- filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name);
+ filename = ldb_relative_path(ldb,
+ tmp_ctx,
+ "sam.ldb.d/metadata.tdb");
+
if (!filename) {
talloc_free(tmp_ctx);
return ldb_oom(ldb);
/* While provisioning, sam.ldb.d directory may not exist,
* so create it. Ignore errors, if it already exists. */
- dirname = talloc_asprintf(tmp_ctx, "%s.d", sam_name);
+ dirname = ldb_relative_path(ldb,
+ tmp_ctx,
+ "sam.ldb.d");
if (!dirname) {
talloc_free(tmp_ctx);
return ldb_oom(ldb);
lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
struct loadparm_context);
- data->metadata->db = tdb_wrap_open(data->metadata, filename, 10,
- TDB_DEFAULT, open_flags, 0660,
- lp_ctx);
+ tdb_flags = lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT|TDB_SEQNUM);
+
+ ldb_flags = ldb_module_flags(ldb);
+
+ if (ldb_flags & LDB_FLG_NOSYNC) {
+ tdb_flags |= TDB_NOSYNC;
+ }
+
+ data->metadata->db = tdb_wrap_open(
+ data->metadata, filename, 10,
+ tdb_flags, open_flags, 0660);
if (data->metadata->db == NULL) {
talloc_free(tmp_ctx);
if (create) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "partition_metadata: Unable to create %s",
- filename);
+ ldb_asprintf_errstring(ldb, "partition_metadata: Unable to create %s: %s",
+ filename, strerror(errno));
+ } else {
+ ldb_asprintf_errstring(ldb, "partition_metadata: Unable to open %s: %s",
+ filename, strerror(errno));
+ }
+ if (errno == EACCES || errno == EPERM) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
return LDB_ERR_OPERATIONS_ERROR;
}
*/
static int partition_metadata_set_sequence_number(struct ldb_module *module)
{
- struct partition_private_data *data;
- struct ldb_result *res;
- struct ldb_request *req;
- struct ldb_seqnum_request *seq;
- struct ldb_seqnum_result *seqr;
- struct ldb_extended *ext;
- TALLOC_CTX *tmp_ctx;
int ret;
uint64_t seq_number;
- data = talloc_get_type_abort(ldb_module_get_private(module),
- struct partition_private_data);
- if (!data || !data->metadata) {
- return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
- "partition_metadata: metadata not initialized");
- }
-
- tmp_ctx = talloc_new(data->metadata);
- if (tmp_ctx == NULL) {
- return ldb_module_oom(module);
- }
-
- res = talloc_zero(tmp_ctx, struct ldb_result);
- if (res == NULL) {
- talloc_free(tmp_ctx);
- return ldb_module_oom(module);
- }
-
- seq = talloc_zero(tmp_ctx, struct ldb_seqnum_request);
- if (seq == NULL) {
- talloc_free(tmp_ctx);
- return ldb_module_oom(module);
- }
- seq->type = LDB_SEQ_HIGHEST_SEQ;
-
- /* Build an extended request, so it can be passed to each partition in
- partition_sequence_number_from_partitions() */
- ret = ldb_build_extended_req(&req,
- ldb_module_get_ctx(module),
- tmp_ctx,
- LDB_EXTENDED_SEQUENCE_NUMBER,
- seq,
- NULL,
- res,
- ldb_extended_default_callback,
- NULL);
- LDB_REQ_SET_LOCATION(req);
+ ret = partition_sequence_number_from_partitions(module, &seq_number);
if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return ret;
- }
-
- ret = partition_sequence_number_from_partitions(module, req, &ext);
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
return ret;
}
- seqr = talloc_get_type_abort(ext->data, struct ldb_seqnum_result);
- seq_number = seqr->seq_num;
-
- talloc_free(tmp_ctx);
-
return partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, seq_number, true);
}
ret = partition_metadata_open(module, false);
if (ret == LDB_SUCCESS) {
- goto end;
+ /* Great, we got the DB open */
+ return LDB_SUCCESS;
}
/* metadata.tdb does not exist, create it */
- DEBUG(2, ("partition_metadata: Migrating partition metadata\n"));
+ DEBUG(2, ("partition_metadata: Migrating partition metadata: "
+ "open of metadata.tdb gave: %s\n",
+ ldb_errstring(ldb_module_get_ctx(module))));
ret = partition_metadata_open(module, true);
if (ret != LDB_SUCCESS) {
- talloc_free(data->metadata);
- data->metadata = NULL;
- goto end;
- }
-
- ret = partition_metadata_set_sequence_number(module);
- if (ret != LDB_SUCCESS) {
- talloc_free(data->metadata);
- data->metadata = NULL;
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "partition_metadata: "
+ "Migrating partition metadata: "
+ "create of metadata.tdb gave: %s\n",
+ ldb_errstring(ldb_module_get_ctx(module)));
+ TALLOC_FREE(data->metadata);
+ return ret;
}
-end:
return ret;
}
*/
int partition_metadata_sequence_number(struct ldb_module *module, uint64_t *value)
{
- return partition_metadata_get_uint64(module,
- LDB_METADATA_SEQ_NUM,
- value,
- 0);
+
+ /* We have to lock all the databases as otherwise we can
+ * return a sequence number that is higher than the DB values
+ * that we can see, as those transactions close after the
+ * metadata.tdb transaction closes */
+ int ret = partition_read_lock(module);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /*
+ * This means we will give a 0 until the first write
+ * tranaction, which is actually pretty reasonable.
+ *
+ * All modern databases will have the metadata.tdb from
+ * the time of the first transaction in provision anyway.
+ */
+ ret = partition_metadata_get_uint64(module,
+ LDB_METADATA_SEQ_NUM,
+ value,
+ 0);
+ if (ret == LDB_SUCCESS) {
+ ret = partition_read_unlock(module);
+ } else {
+ /* Don't overwrite the error code */
+ partition_read_unlock(module);
+ }
+ return ret;
+
}
return ret;
}
+ if (*value == 0) {
+ /*
+ * We are in a transaction now, so we can get the
+ * sequence number from the partitions.
+ */
+ ret = partition_metadata_set_sequence_number(module);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(data->metadata);
+ partition_del_trans(module);
+ return ret;
+ }
+
+ ret = partition_metadata_get_uint64(module,
+ LDB_METADATA_SEQ_NUM,
+ value, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
(*value)++;
ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
return ret;
if (tdb_transaction_start(tdb) != 0) {
return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
- tdb_errorstr_compat(tdb));
+ tdb_errorstr(tdb));
}
data->metadata->in_transaction++;
if (tdb_transaction_prepare_commit(tdb) != 0) {
return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
- tdb_errorstr_compat(tdb));
+ tdb_errorstr(tdb));
}
return LDB_SUCCESS;
if (tdb_transaction_commit(tdb) != 0) {
return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
- tdb_errorstr_compat(tdb));
+ tdb_errorstr(tdb));
}
return LDB_SUCCESS;