s4:dsdb/subtree_delete: do the recursive delete AS_SYSTEM/TRUSTED (bug #7711)
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / partition_metadata.c
blob5826ac2ee1128ede0f89914f9d7e5b6af22e5822
1 /*
2 Partitions ldb module - management of metadata.tdb for sequence number
4 Copyright (C) Amitay Isaacs <amitay@samba.org> 2011
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "dsdb/samdb/ldb_modules/partition.h"
21 #include "system/filesys.h"
23 #define LDB_METADATA_SEQ_NUM "SEQ_NUM"
27 * Read a key with uint64 value
29 static int partition_metadata_get_uint64(struct ldb_module *module,
30 const char *key, uint64_t *value,
31 uint64_t default_value)
33 struct partition_private_data *data;
34 struct tdb_context *tdb;
35 TDB_DATA tdb_key, tdb_data;
36 char *value_str;
37 TALLOC_CTX *tmp_ctx;
39 data = talloc_get_type_abort(ldb_module_get_private(module),
40 struct partition_private_data);
42 if (!data || !data->metadata || !data->metadata->db) {
43 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
44 "partition_metadata: metadata tdb not initialized");
47 tmp_ctx = talloc_new(NULL);
48 if (tmp_ctx == NULL) {
49 return ldb_module_oom(module);
52 tdb = data->metadata->db->tdb;
54 tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
55 tdb_key.dsize = strlen(key);
57 tdb_data = tdb_fetch(tdb, tdb_key);
58 if (!tdb_data.dptr) {
59 if (tdb_error(tdb) == TDB_ERR_NOEXIST) {
60 *value = default_value;
61 return LDB_SUCCESS;
62 } else {
63 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
64 tdb_errorstr(tdb));
68 value_str = talloc_strndup(tmp_ctx, (char *)tdb_data.dptr, tdb_data.dsize);
69 if (value_str == NULL) {
70 SAFE_FREE(tdb_data.dptr);
71 talloc_free(tmp_ctx);
72 return ldb_module_oom(module);
75 *value = strtoull(value_str, NULL, 10);
77 SAFE_FREE(tdb_data.dptr);
78 talloc_free(tmp_ctx);
80 return LDB_SUCCESS;
85 * Write a key with uin64 value
87 static int partition_metadata_set_uint64(struct ldb_module *module,
88 const char *key, uint64_t value,
89 bool insert)
91 struct partition_private_data *data;
92 struct tdb_context *tdb;
93 TDB_DATA tdb_key, tdb_data;
94 int tdb_flag;
95 char *value_str;
96 TALLOC_CTX *tmp_ctx;
98 data = talloc_get_type_abort(ldb_module_get_private(module),
99 struct partition_private_data);
101 if (!data || !data->metadata || !data->metadata->db) {
102 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
103 "partition_metadata: metadata tdb not initialized");
106 tmp_ctx = talloc_new(NULL);
107 if (tmp_ctx == NULL) {
108 return ldb_module_oom(module);
111 tdb = data->metadata->db->tdb;
113 value_str = talloc_asprintf(tmp_ctx, "%llu", (unsigned long long)value);
114 if (value_str == NULL) {
115 talloc_free(tmp_ctx);
116 return ldb_module_oom(module);
119 tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
120 tdb_key.dsize = strlen(key);
122 tdb_data.dptr = (uint8_t *)value_str;
123 tdb_data.dsize = strlen(value_str);
125 if (insert) {
126 tdb_flag = TDB_INSERT;
127 } else {
128 tdb_flag = TDB_MODIFY;
131 if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) {
132 talloc_free(tmp_ctx);
133 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
134 tdb_errorstr(tdb));
137 talloc_free(tmp_ctx);
139 return LDB_SUCCESS;
142 int partition_metadata_inc_schema_sequence(struct ldb_module *module)
144 struct partition_private_data *data;
145 int ret;
146 uint64_t value;
148 data = talloc_get_type_abort(ldb_module_get_private(module),
149 struct partition_private_data);
150 if (!data || !data->metadata) {
151 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
152 "partition_metadata: metadata not initialized");
155 if (data->metadata->in_transaction == 0) {
156 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
157 "partition_metadata: increment sequence number without transaction");
159 ret = partition_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0);
160 if (ret != LDB_SUCCESS) {
161 return ret;
164 value++;
165 ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, false);
166 if (ret == LDB_ERR_OPERATIONS_ERROR) {
167 /* Modify failed, let's try the add */
168 ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, true);
170 return ret;
176 * Open sam.ldb.d/metadata.tdb.
178 static int partition_metadata_open(struct ldb_module *module, bool create)
180 struct ldb_context *ldb = ldb_module_get_ctx(module);
181 TALLOC_CTX *tmp_ctx;
182 struct partition_private_data *data;
183 struct loadparm_context *lp_ctx;
184 const char *sam_name;
185 char *filename, *dirname;
186 int open_flags;
187 struct stat statbuf;
189 data = talloc_get_type_abort(ldb_module_get_private(module),
190 struct partition_private_data);
191 if (!data || !data->metadata) {
192 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
193 "partition_metadata: metadata not initialized");
196 tmp_ctx = talloc_new(NULL);
197 if (tmp_ctx == NULL) {
198 return ldb_module_oom(module);
201 sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url");
202 if (strncmp("tdb://", sam_name, 6) == 0) {
203 sam_name += 6;
205 if (!sam_name) {
206 talloc_free(tmp_ctx);
207 return ldb_operr(ldb);
209 filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name);
210 if (!filename) {
211 talloc_free(tmp_ctx);
212 return ldb_oom(ldb);
215 open_flags = O_RDWR;
216 if (create) {
217 open_flags |= O_CREAT;
219 /* While provisioning, sam.ldb.d directory may not exist,
220 * so create it. Ignore errors, if it already exists. */
221 dirname = talloc_asprintf(tmp_ctx, "%s.d", sam_name);
222 if (!dirname) {
223 talloc_free(tmp_ctx);
224 return ldb_oom(ldb);
227 mkdir(dirname, 0700);
228 talloc_free(dirname);
229 } else {
230 if (stat(filename, &statbuf) != 0) {
231 talloc_free(tmp_ctx);
232 return LDB_ERR_OPERATIONS_ERROR;
236 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
237 struct loadparm_context);
239 data->metadata->db = tdb_wrap_open(data->metadata, filename, 10,
240 TDB_DEFAULT, open_flags, 0660,
241 lp_ctx);
242 if (data->metadata->db == NULL) {
243 talloc_free(tmp_ctx);
244 if (create) {
245 ldb_debug(ldb, LDB_DEBUG_ERROR,
246 "partition_metadata: Unable to create %s",
247 filename);
249 return LDB_ERR_OPERATIONS_ERROR;
252 talloc_free(tmp_ctx);
253 return LDB_SUCCESS;
258 * Set the sequence number calculated from older logic (sum of primary sequence
259 * numbers for each partition) as LDB_METADATA_SEQ_NUM key.
261 static int partition_metadata_set_sequence_number(struct ldb_module *module)
263 int ret;
264 uint64_t seq_number;
266 ret = partition_sequence_number_from_partitions(module, &seq_number);
267 if (ret != LDB_SUCCESS) {
268 return ret;
271 return partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, seq_number, true);
276 * Initialize metadata. Load metadata.tdb.
277 * If missing, create it and fill in sequence number
279 int partition_metadata_init(struct ldb_module *module)
281 struct partition_private_data *data;
282 int ret;
284 data = talloc_get_type_abort(ldb_module_get_private(module),
285 struct partition_private_data);
287 data->metadata = talloc_zero(data, struct partition_metadata);
288 if (data->metadata == NULL) {
289 return ldb_module_oom(module);
292 ret = partition_metadata_open(module, false);
293 if (ret == LDB_SUCCESS) {
294 goto end;
297 /* metadata.tdb does not exist, create it */
298 DEBUG(2, ("partition_metadata: Migrating partition metadata\n"));
299 ret = partition_metadata_open(module, true);
300 if (ret != LDB_SUCCESS) {
301 talloc_free(data->metadata);
302 data->metadata = NULL;
303 goto end;
306 ret = partition_metadata_set_sequence_number(module);
307 if (ret != LDB_SUCCESS) {
308 talloc_free(data->metadata);
309 data->metadata = NULL;
312 end:
313 return ret;
318 * Read the sequence number, default to 0 if LDB_METADATA_SEQ_NUM key is missing
320 int partition_metadata_sequence_number(struct ldb_module *module, uint64_t *value)
322 return partition_metadata_get_uint64(module,
323 LDB_METADATA_SEQ_NUM,
324 value,
330 * Increment the sequence number, returning the new sequence number
332 int partition_metadata_sequence_number_increment(struct ldb_module *module, uint64_t *value)
334 struct partition_private_data *data;
335 int ret;
337 data = talloc_get_type_abort(ldb_module_get_private(module),
338 struct partition_private_data);
339 if (!data || !data->metadata) {
340 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
341 "partition_metadata: metadata not initialized");
344 if (data->metadata->in_transaction == 0) {
345 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
346 "partition_metadata: increment sequence number without transaction");
349 ret = partition_metadata_get_uint64(module, LDB_METADATA_SEQ_NUM, value, 0);
350 if (ret != LDB_SUCCESS) {
351 return ret;
354 (*value)++;
355 ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
356 return ret;
361 * Transaction start
363 int partition_metadata_start_trans(struct ldb_module *module)
365 struct partition_private_data *data;
366 struct tdb_context *tdb;
368 data = talloc_get_type_abort(ldb_module_get_private(module),
369 struct partition_private_data);
370 if (!data || !data->metadata || !data->metadata->db) {
371 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
372 "partition_metadata: metadata not initialized");
374 tdb = data->metadata->db->tdb;
376 if (tdb_transaction_start(tdb) != 0) {
377 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
378 tdb_errorstr(tdb));
381 data->metadata->in_transaction++;
383 return LDB_SUCCESS;
388 * Transaction prepare commit
390 int partition_metadata_prepare_commit(struct ldb_module *module)
392 struct partition_private_data *data;
393 struct tdb_context *tdb;
395 data = talloc_get_type_abort(ldb_module_get_private(module),
396 struct partition_private_data);
397 if (!data || !data->metadata || !data->metadata->db) {
398 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
399 "partition_metadata: metadata not initialized");
401 tdb = data->metadata->db->tdb;
403 if (data->metadata->in_transaction == 0) {
404 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
405 "partition_metadata: not in transaction");
408 if (tdb_transaction_prepare_commit(tdb) != 0) {
409 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
410 tdb_errorstr(tdb));
413 return LDB_SUCCESS;
418 * Transaction end
420 int partition_metadata_end_trans(struct ldb_module *module)
422 struct partition_private_data *data;
423 struct tdb_context *tdb;
425 data = talloc_get_type_abort(ldb_module_get_private(module),
426 struct partition_private_data);
427 if (!data || !data->metadata || !data->metadata->db) {
428 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
429 "partition_metadata: metadata not initialized");
431 tdb = data->metadata->db->tdb;
433 if (data->metadata->in_transaction == 0) {
434 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
435 "partition_metadata: not in transaction");
438 data->metadata->in_transaction--;
440 if (tdb_transaction_commit(tdb) != 0) {
441 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
442 tdb_errorstr(tdb));
445 return LDB_SUCCESS;
450 * Transaction delete
452 int partition_metadata_del_trans(struct ldb_module *module)
454 struct partition_private_data *data;
455 struct tdb_context *tdb;
457 data = talloc_get_type_abort(ldb_module_get_private(module),
458 struct partition_private_data);
459 if (!data || !data->metadata || !data->metadata->db) {
460 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
461 "partition_metadata: metadata not initialized");
463 tdb = data->metadata->db->tdb;
465 if (data->metadata->in_transaction == 0) {
466 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
467 "partition_metadata: not in transaction");
470 data->metadata->in_transaction--;
472 tdb_transaction_cancel(tdb);
474 return LDB_SUCCESS;