libndr: Apply endianness flags to subndr
[Samba.git] / source3 / rpc_server / fss / srv_fss_state.c
blob8597c36a74ebaae1a8d6f485ac289f7d2e3f902d
1 /*
2 * File Server Remote VSS Protocol (FSRVP) persistent server state
4 * Copyright (C) David Disseldorp 2012-2015
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 "source3/include/includes.h"
21 #include <fcntl.h>
22 #include "source3/include/util_tdb.h"
23 #include "lib/dbwrap/dbwrap.h"
24 #include "lib/dbwrap/dbwrap_open.h"
25 #include "librpc/ndr/libndr.h"
26 #include "librpc/gen_ndr/ndr_fsrvp_state.h"
27 #include "srv_fss_private.h"
29 #define FSS_DB_KEY_VERSION "db_version"
30 #define FSS_DB_KEY_CONTEXT "context"
31 #define FSS_DB_KEY_SC_SET_COUNT "sc_set_count"
32 #define FSS_DB_KEY_PFX_SC_SET "sc_set/"
33 #define FSS_DB_KEY_PFX_SC "sc/"
34 #define FSS_DB_KEY_PFX_SMAP "smap/"
36 static NTSTATUS fss_state_smap_store(TALLOC_CTX *mem_ctx,
37 struct db_context *db,
38 const char *sc_key_str,
39 struct fss_sc_smap *smap)
41 NTSTATUS status;
42 TDB_DATA val;
43 const char *smap_key_str;
44 struct fsrvp_state_smap smap_state;
45 enum ndr_err_code ndr_ret;
46 DATA_BLOB smap_state_blob;
48 /* becomes sc_set/@sc_set_id/sc/@sc_id/smap/@sc_share_name */
49 smap_key_str = talloc_asprintf(mem_ctx, "%s/%s%s", sc_key_str,
50 FSS_DB_KEY_PFX_SMAP,
51 smap->sc_share_name);
52 if (smap_key_str == NULL) {
53 return NT_STATUS_NO_MEMORY;
56 smap_state.share_name = smap->share_name;
57 smap_state.sc_share_name = smap->sc_share_name;
58 /* @smap->sc_share_comment may be null if not exposed. */
59 if (smap->sc_share_comment != NULL) {
60 smap_state.sc_share_comment = smap->sc_share_comment;
61 } else {
62 smap_state.sc_share_comment = "";
64 smap_state.is_exposed = smap->is_exposed;
66 ndr_ret = ndr_push_struct_blob(&smap_state_blob, mem_ctx,
67 &smap_state,
68 (ndr_push_flags_fn_t)ndr_push_fsrvp_state_smap);
69 if (ndr_ret != NDR_ERR_SUCCESS) {
70 return NT_STATUS_INTERNAL_ERROR;
73 val.dsize = smap_state_blob.length;
74 val.dptr = smap_state_blob.data;
76 status = dbwrap_store(db, string_term_tdb_data(smap_key_str), val, 0);
77 if (!NT_STATUS_IS_OK(status)) {
78 return status;
81 return NT_STATUS_OK;
84 static NTSTATUS fss_state_sc_store(TALLOC_CTX *mem_ctx,
85 struct db_context *db,
86 const char *sc_set_key_str,
87 struct fss_sc *sc)
89 NTSTATUS status;
90 TDB_DATA val;
91 const char *sc_key_str;
92 struct fsrvp_state_sc sc_state;
93 struct fss_sc_smap *smap;
94 enum ndr_err_code ndr_ret;
95 DATA_BLOB sc_state_blob;
97 /* becomes sc_set/@sc_set.id/sc/@sc_id */
98 sc_key_str = talloc_asprintf(mem_ctx, "%s/%s%s", sc_set_key_str,
99 FSS_DB_KEY_PFX_SC, sc->id_str);
100 if (sc_key_str == NULL) {
101 return NT_STATUS_NO_MEMORY;
104 sc_state.id_str = sc->id_str;
105 sc_state.volume_name = sc->volume_name;
106 /* @sc->sc_path may be null if not committed, store empty str */
107 sc_state.sc_path = (sc->sc_path ? sc->sc_path : "");
108 sc_state.create_ts = sc->create_ts;
109 sc_state.smaps_count = sc->smaps_count;
111 ndr_ret = ndr_push_struct_blob(&sc_state_blob, mem_ctx,
112 &sc_state,
113 (ndr_push_flags_fn_t)ndr_push_fsrvp_state_sc);
114 if (ndr_ret != NDR_ERR_SUCCESS) {
115 return NT_STATUS_INTERNAL_ERROR;
118 val.dsize = sc_state_blob.length;
119 val.dptr = sc_state_blob.data;
121 status = dbwrap_store(db, string_term_tdb_data(sc_key_str), val, 0);
122 if (!NT_STATUS_IS_OK(status)) {
123 return status;
126 for (smap = sc->smaps; smap; smap = smap->next) {
127 status = fss_state_smap_store(mem_ctx, db, sc_key_str, smap);
128 if (!NT_STATUS_IS_OK(status)) {
129 return status;
133 return NT_STATUS_OK;
136 static NTSTATUS fss_state_sc_set_store(TALLOC_CTX *mem_ctx,
137 struct db_context *db,
138 struct fss_sc_set *sc_set)
140 NTSTATUS status;
141 TDB_DATA val;
142 const char *sc_set_key_str;
143 struct fss_sc *sc;
144 struct fsrvp_state_sc_set sc_set_state;
145 DATA_BLOB sc_set_state_blob;
146 enum ndr_err_code ndr_ret;
148 sc_set_key_str = talloc_asprintf(mem_ctx, "%s%s",
149 FSS_DB_KEY_PFX_SC_SET,
150 sc_set->id_str);
151 if (sc_set_key_str == NULL) {
152 return NT_STATUS_NO_MEMORY;
155 sc_set_state.id_str = sc_set->id_str;
156 sc_set_state.state = sc_set->state;
157 sc_set_state.context = sc_set->context;
158 sc_set_state.scs_count = sc_set->scs_count;
160 ndr_ret = ndr_push_struct_blob(&sc_set_state_blob, mem_ctx,
161 &sc_set_state,
162 (ndr_push_flags_fn_t)ndr_push_fsrvp_state_sc_set);
163 if (ndr_ret != NDR_ERR_SUCCESS) {
164 return NT_STATUS_INTERNAL_ERROR;
167 val.dsize = sc_set_state_blob.length;
168 val.dptr = sc_set_state_blob.data;
170 status = dbwrap_store(db, string_term_tdb_data(sc_set_key_str), val, 0);
171 if (!NT_STATUS_IS_OK(status)) {
172 return status;
175 for (sc = sc_set->scs; sc; sc = sc->next) {
176 status = fss_state_sc_store(mem_ctx, db, sc_set_key_str, sc);
177 if (!NT_STATUS_IS_OK(status)) {
178 return status;
182 return NT_STATUS_OK;
186 * write out the current fsrvp server state to a TDB. This clears any content
187 * currently written to the TDB.
189 _PRIVATE_ NTSTATUS fss_state_store(TALLOC_CTX *mem_ctx,
190 struct fss_sc_set *sc_sets,
191 uint32_t sc_sets_count,
192 const char *db_path)
194 TALLOC_CTX *tmp_ctx;
195 struct db_context *db;
196 NTSTATUS status;
197 int ret;
198 struct fss_sc_set *sc_set;
200 tmp_ctx = talloc_new(mem_ctx);
201 if (tmp_ctx == NULL) {
202 return NT_STATUS_NO_MEMORY;
205 db = db_open(tmp_ctx, db_path, 0, TDB_DEFAULT, O_RDWR | O_CREAT,
206 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
207 if (db == NULL) {
208 DEBUG(0, ("Failed to open fss state database %s\n", db_path));
209 status = NT_STATUS_ACCESS_DENIED;
210 goto err_ctx_free;
213 ret = dbwrap_wipe(db);
214 if (ret != 0) {
215 status = NT_STATUS_UNSUCCESSFUL;
216 goto err_db_free;
219 status = dbwrap_store_int32_bystring(db, FSS_DB_KEY_VERSION,
220 FSRVP_STATE_DB_VERSION);
221 if (!NT_STATUS_IS_OK(status)) {
222 goto err_db_free;
225 ret = dbwrap_transaction_start(db);
226 if (ret != 0) {
227 status = NT_STATUS_UNSUCCESSFUL;
228 goto err_db_free;
231 status = dbwrap_store_int32_bystring(db, FSS_DB_KEY_SC_SET_COUNT,
232 sc_sets_count);
233 if (!NT_STATUS_IS_OK(status)) {
234 status = NT_STATUS_UNSUCCESSFUL;
235 goto err_trans_cancel;
238 for (sc_set = sc_sets; sc_set; sc_set = sc_set->next) {
239 status = fss_state_sc_set_store(tmp_ctx, db, sc_set);
240 if (!NT_STATUS_IS_OK(status)) {
241 goto err_trans_cancel;
245 ret = dbwrap_transaction_commit(db);
246 if (ret != 0) {
247 status = NT_STATUS_UNSUCCESSFUL;
248 goto err_trans_cancel;
251 talloc_free(db);
252 talloc_free(tmp_ctx);
253 return NT_STATUS_OK;
255 err_trans_cancel:
256 dbwrap_transaction_cancel(db);
257 err_db_free:
258 talloc_free(db);
259 err_ctx_free:
260 talloc_free(tmp_ctx);
261 return status;
264 static NTSTATUS fss_state_smap_retrieve(TALLOC_CTX *mem_ctx,
265 TDB_DATA *key,
266 TDB_DATA *val,
267 struct fss_sc_smap **smap_out)
269 struct fss_sc_smap *smap;
270 struct fsrvp_state_smap smap_state;
271 DATA_BLOB smap_state_blob;
272 enum ndr_err_code ndr_ret;
274 smap_state_blob.length = val->dsize;
275 smap_state_blob.data = val->dptr;
277 ndr_ret = ndr_pull_struct_blob(&smap_state_blob, mem_ctx, &smap_state,
278 (ndr_pull_flags_fn_t)ndr_pull_fsrvp_state_smap);
279 if (ndr_ret != NDR_ERR_SUCCESS) {
280 return NT_STATUS_INTERNAL_ERROR;
283 smap = talloc_zero(mem_ctx, struct fss_sc_smap);
284 if (smap == NULL) {
285 return NT_STATUS_NO_MEMORY;
288 smap->share_name = talloc_strdup(smap, smap_state.share_name);
289 if (smap->share_name == NULL) {
290 return NT_STATUS_NO_MEMORY;
293 /* store the full path so that the hierarchy can be rebuilt */
294 smap->sc_share_name = talloc_strdup(smap, (char *)key->dptr);
295 if (smap->sc_share_name == NULL) {
296 return NT_STATUS_NO_MEMORY;
299 /* sc_share_comment may be empty, keep null in such a case */
300 if (strlen(smap_state.sc_share_comment) > 0) {
301 smap->sc_share_comment = talloc_strdup(smap,
302 smap_state.sc_share_comment);
303 if (smap->sc_share_comment == NULL) {
304 return NT_STATUS_NO_MEMORY;
308 smap->is_exposed = smap_state.is_exposed;
310 *smap_out = smap;
311 return NT_STATUS_OK;
314 static NTSTATUS fss_state_sc_retrieve(TALLOC_CTX *mem_ctx,
315 TDB_DATA *key,
316 TDB_DATA *val,
317 struct fss_sc **sc_out)
319 struct fss_sc *sc;
320 struct fsrvp_state_sc sc_state;
321 DATA_BLOB sc_state_blob;
322 enum ndr_err_code ndr_ret;
324 sc_state_blob.length = val->dsize;
325 sc_state_blob.data = val->dptr;
327 ndr_ret = ndr_pull_struct_blob(&sc_state_blob, mem_ctx, &sc_state,
328 (ndr_pull_flags_fn_t)ndr_pull_fsrvp_state_sc);
329 if (ndr_ret != NDR_ERR_SUCCESS) {
330 return NT_STATUS_INTERNAL_ERROR;
333 sc = talloc_zero(mem_ctx, struct fss_sc);
334 if (sc == NULL) {
335 return NT_STATUS_NO_MEMORY;
338 /* store the full path so that the hierarchy can be rebuilt */
339 sc->id_str = talloc_strdup(sc, (char *)key->dptr);
340 if (sc->id_str == NULL) {
341 return NT_STATUS_NO_MEMORY;
344 sc->volume_name = talloc_strdup(sc, sc_state.volume_name);
345 if (sc->volume_name == NULL) {
346 return NT_STATUS_NO_MEMORY;
349 /* sc_path may be empty, keep null in such a case */
350 if (strlen(sc_state.sc_path) > 0) {
351 sc->sc_path = talloc_strdup(sc, sc_state.sc_path);
352 if (sc->sc_path == NULL) {
353 return NT_STATUS_NO_MEMORY;
356 sc->create_ts = sc_state.create_ts;
357 sc->smaps_count = sc_state.smaps_count;
359 *sc_out = sc;
360 return NT_STATUS_OK;
363 static NTSTATUS fss_state_sc_set_retrieve(TALLOC_CTX *mem_ctx,
364 TDB_DATA *key,
365 TDB_DATA *val,
366 struct fss_sc_set **sc_set_out)
368 struct fss_sc_set *sc_set;
369 struct fsrvp_state_sc_set sc_set_state;
370 DATA_BLOB sc_set_state_blob;
371 enum ndr_err_code ndr_ret;
373 sc_set_state_blob.length = val->dsize;
374 sc_set_state_blob.data = val->dptr;
376 ndr_ret = ndr_pull_struct_blob(&sc_set_state_blob, mem_ctx,
377 &sc_set_state,
378 (ndr_pull_flags_fn_t)ndr_pull_fsrvp_state_sc_set);
379 if (ndr_ret != NDR_ERR_SUCCESS) {
380 return NT_STATUS_INTERNAL_ERROR;
383 sc_set = talloc_zero(mem_ctx, struct fss_sc_set);
384 if (sc_set == NULL) {
385 return NT_STATUS_NO_MEMORY;
388 /* store the full path so that the hierarchy can be rebuilt */
389 sc_set->id_str = talloc_strdup(sc_set, (char *)key->dptr);
390 if (sc_set->id_str == NULL) {
391 return NT_STATUS_NO_MEMORY;
393 sc_set->state = sc_set_state.state;
394 sc_set->context = sc_set_state.context;
395 sc_set->scs_count = sc_set_state.scs_count;
397 *sc_set_out = sc_set;
398 return NT_STATUS_OK;
401 struct fss_traverse_state {
402 TALLOC_CTX *mem_ctx;
403 struct fss_sc_smap *smaps;
404 uint32_t smaps_count;
405 struct fss_sc *scs;
406 uint32_t scs_count;
407 struct fss_sc_set *sc_sets;
408 uint32_t sc_sets_count;
409 NTSTATUS (*smap_retrieve)(TALLOC_CTX *mem_ctx,
410 TDB_DATA *key,
411 TDB_DATA *val,
412 struct fss_sc_smap **smap_out);
413 NTSTATUS (*sc_retrieve)(TALLOC_CTX *mem_ctx,
414 TDB_DATA *key,
415 TDB_DATA *val,
416 struct fss_sc **sc_out);
417 NTSTATUS (*sc_set_retrieve)(TALLOC_CTX *mem_ctx,
418 TDB_DATA *key,
419 TDB_DATA *val,
420 struct fss_sc_set **sc_set_out);
423 static int fss_state_retrieve_traverse(struct db_record *rec,
424 void *private_data)
426 NTSTATUS status;
427 struct fss_traverse_state *trv_state
428 = (struct fss_traverse_state *)private_data;
429 TDB_DATA key = dbwrap_record_get_key(rec);
430 TDB_DATA val = dbwrap_record_get_value(rec);
432 /* order of checking is important here */
433 if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SMAP) != NULL) {
434 struct fss_sc_smap *smap;
435 status = trv_state->smap_retrieve(trv_state->mem_ctx,
436 &key, &val, &smap);
437 if (!NT_STATUS_IS_OK(status)) {
438 return -1;
440 DLIST_ADD_END(trv_state->smaps, smap);
441 trv_state->smaps_count++;
442 } else if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SC) != NULL) {
443 struct fss_sc *sc;
444 status = trv_state->sc_retrieve(trv_state->mem_ctx,
445 &key, &val, &sc);
446 if (!NT_STATUS_IS_OK(status)) {
447 return -1;
449 DLIST_ADD_END(trv_state->scs, sc);
450 trv_state->scs_count++;
451 } else if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SC_SET) != NULL) {
452 struct fss_sc_set *sc_set;
453 status = trv_state->sc_set_retrieve(trv_state->mem_ctx,
454 &key, &val, &sc_set);
455 if (!NT_STATUS_IS_OK(status)) {
456 return -1;
458 DLIST_ADD_END(trv_state->sc_sets, sc_set);
459 trv_state->sc_sets_count++;
460 } else {
461 /* global context and db vers */
462 DEBUG(4, ("Ignoring fss srv db entry with key %s\n", key.dptr));
465 return 0;
468 static bool fss_state_smap_is_child(struct fss_sc *sc,
469 struct fss_sc_smap *smap)
471 return (strstr(smap->sc_share_name, sc->id_str) != NULL);
474 static NTSTATUS fss_state_hierarchize_smaps(struct fss_traverse_state *trv_state,
475 struct fss_sc *sc)
477 struct fss_sc_smap *smap;
478 struct fss_sc_smap *smap_n;
479 uint32_t smaps_moved = 0;
481 for (smap = trv_state->smaps; smap; smap = smap_n) {
482 smap_n = smap->next;
483 if (!fss_state_smap_is_child(sc, smap))
484 continue;
486 /* smap mem should be owned by parent sc */
487 talloc_steal(sc, smap);
488 DLIST_REMOVE(trv_state->smaps, smap);
489 trv_state->smaps_count--;
490 DLIST_ADD_END(sc->smaps, smap);
491 smaps_moved++;
493 /* last component of the tdb key path is the sc share name */
494 SMB_ASSERT(strrchr(smap->sc_share_name, '/') != NULL);
495 smap->sc_share_name = strrchr(smap->sc_share_name, '/') + 1;
498 if (sc->smaps_count != smaps_moved) {
499 DEBUG(0, ("Inconsistent smaps_count, expected %u, moved %u\n",
500 sc->smaps_count, smaps_moved));
501 return NT_STATUS_UNSUCCESSFUL;
504 return NT_STATUS_OK;
507 static bool fss_state_sc_is_child(struct fss_sc_set *sc_set,
508 struct fss_sc *sc)
510 return (strstr(sc->id_str, sc_set->id_str) != NULL);
513 static NTSTATUS fss_state_hierarchize_scs(struct fss_traverse_state *trv_state,
514 struct fss_sc_set *sc_set)
516 NTSTATUS status;
517 struct fss_sc *sc;
518 struct fss_sc *sc_n;
519 uint32_t scs_moved = 0;
521 for (sc = trv_state->scs; sc; sc = sc_n) {
522 sc_n = sc->next;
523 if (!fss_state_sc_is_child(sc_set, sc))
524 continue;
526 /* sc mem should be owned by parent sc_set */
527 talloc_steal(sc_set, sc);
528 DLIST_REMOVE(trv_state->scs, sc);
529 trv_state->scs_count--;
530 DLIST_ADD_END(sc_set->scs, sc);
531 scs_moved++;
533 sc->sc_set = sc_set;
535 /* last component of the tdb key path is the sc GUID str */
536 SMB_ASSERT(strrchr(sc->id_str, '/') != NULL);
537 sc->id_str = strrchr(sc->id_str, '/') + 1;
539 status = GUID_from_string(sc->id_str, &sc->id);
540 if (!NT_STATUS_IS_OK(status)) {
541 goto err_out;
544 status = fss_state_hierarchize_smaps(trv_state, sc);
545 if (!NT_STATUS_IS_OK(status)) {
546 goto err_out;
550 if (sc_set->scs_count != scs_moved) {
551 DEBUG(0, ("Inconsistent scs_count, expected %u, moved %u\n",
552 sc_set->scs_count, scs_moved));
553 status = NT_STATUS_UNSUCCESSFUL;
554 goto err_out;
557 return NT_STATUS_OK;
559 err_out:
560 return status;
563 static NTSTATUS fss_state_hierarchize(struct fss_traverse_state *trv_state,
564 struct fss_sc_set **sc_sets,
565 uint32_t *sc_sets_count)
567 NTSTATUS status;
568 struct fss_sc_set *sc_set;
569 struct fss_sc_set *sc_set_n;
570 uint32_t i = 0;
572 *sc_sets = NULL;
573 for (sc_set = trv_state->sc_sets; sc_set; sc_set = sc_set_n) {
574 sc_set_n = sc_set->next;
575 /* sc_set mem already owned by trv_state->mem_ctx */
576 DLIST_REMOVE(trv_state->sc_sets, sc_set);
577 trv_state->sc_sets_count--;
578 DLIST_ADD_END(*sc_sets, sc_set);
579 i++;
581 /* last component of the tdb key path is the sc_set GUID str */
582 SMB_ASSERT(strrchr(sc_set->id_str, '/') != NULL);
583 sc_set->id_str = strrchr(sc_set->id_str, '/') + 1;
585 status = GUID_from_string(sc_set->id_str, &sc_set->id);
586 if (!NT_STATUS_IS_OK(status)) {
587 goto err_out;
590 status = fss_state_hierarchize_scs(trv_state, sc_set);
591 if (!NT_STATUS_IS_OK(status)) {
592 goto err_out;
595 *sc_sets_count = i;
596 return NT_STATUS_OK;
598 err_out:
599 return status;
602 _PRIVATE_ NTSTATUS fss_state_retrieve(TALLOC_CTX *mem_ctx,
603 struct fss_sc_set **sc_sets,
604 uint32_t *sc_sets_count,
605 const char *db_path)
607 struct db_context *db;
608 NTSTATUS status;
609 struct fss_traverse_state trv_state;
610 int err;
611 int rec_count;
612 int vers;
613 *sc_sets = NULL;
614 *sc_sets_count = 0;
616 memset(&trv_state, 0, sizeof(trv_state));
617 trv_state.mem_ctx = talloc_new(mem_ctx);
618 if (trv_state.mem_ctx == NULL) {
619 status = NT_STATUS_NO_MEMORY;
620 goto err_out;
623 /* set callbacks for unmarshalling on-disk structures */
624 trv_state.smap_retrieve = fss_state_smap_retrieve;
625 trv_state.sc_retrieve = fss_state_sc_retrieve;
626 trv_state.sc_set_retrieve = fss_state_sc_set_retrieve;
628 db = db_open(trv_state.mem_ctx, db_path, 0, TDB_DEFAULT,
629 O_RDONLY, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
630 err = errno;
631 if ((db == NULL) && (err == ENOENT)) {
632 DEBUG(4, ("fss state TDB does not exist for retrieval\n"));
633 status = NT_STATUS_OK;
634 goto err_ts_free;
635 } else if (db == NULL) {
636 DEBUG(0, ("Failed to open fss state TDB: %s\n",
637 strerror(err)));
638 status = NT_STATUS_ACCESS_DENIED;
639 goto err_ts_free;
642 status = dbwrap_fetch_int32_bystring(db, FSS_DB_KEY_VERSION,
643 &vers);
644 if (!NT_STATUS_IS_OK(status)) {
645 DEBUG(0, ("failed to fetch version from fss state tdb: %s\n",
646 nt_errstr(status)));
647 goto err_db_free;
648 } else if (vers != FSRVP_STATE_DB_VERSION) {
649 DEBUG(0, ("Unsupported fss tdb version %d, expected %d\n",
650 vers, FSRVP_STATE_DB_VERSION));
651 status = NT_STATUS_UNSUCCESSFUL;
652 goto err_db_free;
655 status = dbwrap_traverse_read(db,
656 fss_state_retrieve_traverse,
657 &trv_state,
658 &rec_count);
659 if (!NT_STATUS_IS_OK(status)) {
660 goto err_db_free;
663 status = fss_state_hierarchize(&trv_state, sc_sets, sc_sets_count);
664 if (!NT_STATUS_IS_OK(status)) {
665 DEBUG(0, ("Failed to form fss state hierarchy\n"));
666 goto err_db_free;
669 /* check whether anything was left without a parent */
670 if (trv_state.sc_sets_count != 0) {
671 DEBUG(0, ("%d shadow copy set orphans in %s tdb\n",
672 trv_state.sc_sets_count, db_path));
673 status = NT_STATUS_UNSUCCESSFUL;
674 goto err_db_free;
676 if (trv_state.scs_count != 0) {
677 DEBUG(0, ("%d shadow copy orphans in %s tdb\n",
678 trv_state.scs_count, db_path));
679 status = NT_STATUS_UNSUCCESSFUL;
680 goto err_db_free;
682 if (trv_state.smaps_count != 0) {
683 DEBUG(0, ("%d share map orphans in %s tdb\n",
684 trv_state.smaps_count, db_path));
685 status = NT_STATUS_UNSUCCESSFUL;
686 goto err_db_free;
688 talloc_free(db);
690 return NT_STATUS_OK;
692 err_db_free:
693 talloc_free(db);
694 err_ts_free:
695 talloc_free(trv_state.mem_ctx);
696 err_out:
697 return status;