static int descriptor_prepare_commit(struct ldb_module *module)
{
	struct descriptor_data *descriptor_private =
		talloc_get_type_abort(ldb_module_get_private(module),
		struct descriptor_data);
	struct descriptor_transaction *t = &descriptor_private->transaction;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct descriptor_changes *c, *n;
	int ret;

	DBG_NOTICE("changes: num_registrations=%zu\n",
		   t->changes.num_registrations);
	DBG_NOTICE("changes: num_registered=%zu\n",
		   t->changes.num_registered);

	/*
	 * The security descriptor propagation
	 * needs to apply the inheritance from
	 * an object to itself and/or all it's
	 * children.
	 *
	 * In the initial replication during
	 * a join, we have every object in our
	 * list.
	 *
	 * In order to avoid useless work it's
	 * better to start with toplevel objects and
	 * move down to the leaf object from there.
	 *
	 * So if the parent_guid is also in our list,
	 * we better move the object behind its parent.
	 *
	 * It allows that the recursive processing of
	 * the parent already does the work needed
	 * for the child.
	 *
	 * If we have a list for this directory tree:
	 *
	 *  A
	 *    -> B
	 *        -> C
	 *            -> D
	 *                -> E
	 *
	 * The initial list would have the order D, E, B, A, C
	 *
	 * By still processing from the front, we ensure that,
	 * when D is found to be below C, that E follows because
	 * we keep peeling items off the front for checking and
	 * move them behind their parent.
	 *
	 * So we would go:
	 *
	 * E B A C D
	 *
	 * B A C D E
	 *
	 * A B C D E
	 */
	for (c = t->changes.list; c; c = n) {
		struct descriptor_changes *pc = NULL;
		n = c->next;

		if (c->sort_count >= t->changes.num_registered) {
			/*
			 * This should never happen, but it's
			 * a sanity check in order to avoid
			 * endless loops. Just stop sorting.
			 */
			break;
		}

		/*
		 * Check if we have the parent also in the list.
		 */
		if (!GUID_all_zero((const void*)&c->parent_guid)) {
			TDB_DATA pkey;
			NTSTATUS status;

			pkey = make_tdb_data((const void*)&c->parent_guid,
					     sizeof(c->parent_guid));

			status = dbwrap_parse_record(t->changes.map, pkey,
						     descriptor_changes_parser, &pc);
			if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
				pc = NULL;
				status = NT_STATUS_OK;
			}
			if (!NT_STATUS_IS_OK(status)) {
				ldb_debug(ldb, LDB_DEBUG_FATAL,
					  "dbwrap_parse_record() - %s\n",
					  nt_errstr(status));
				return ldb_module_operr(module);
			}
		}

		if (pc == NULL) {
			/*
			 * There is no parent in the list
			 */
			t->changes.num_toplevel += 1;
			continue;
		}

		/*
		 * Move the child after the parent
		 *
		 * Note that we do that multiple times
		 * in case the parent already moved itself.
		 *
		 * See the comment above the loop.
		 */
		DLIST_REMOVE(t->changes.list, c);
		DLIST_ADD_AFTER(t->changes.list, c, pc);

		/*
		 * Remember how often we moved the object
		 * in order to avoid endless loops.
		 */
		c->sort_count += 1;
	}

	DBG_NOTICE("changes: num_toplevel=%zu\n", t->changes.num_toplevel);

	while (t->changes.list != NULL) {
		c = t->changes.list;

		DLIST_REMOVE(t->changes.list, c);

		/*
		 * Note that descriptor_sd_propagation_recursive()
		 * may also remove other elements of the list,
		 * so we can't use a next pointer
		 */
		ret = descriptor_sd_propagation_recursive(module, c);
		if (ret == LDB_ERR_NO_SUCH_OBJECT) {
			continue;
		}
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	DBG_NOTICE("changes: num_processed=%zu\n", t->changes.num_processed);
	DBG_NOTICE("objects: num_processed=%zu\n", t->objects.num_processed);
	DBG_NOTICE("objects: num_skipped=%zu\n", t->objects.num_skipped);

	return ldb_next_prepare_commit(module);
}
static int descriptor_prepare_commit(struct ldb_module *module)
{
	struct descriptor_data *descriptor_private =
		talloc_get_type_abort(ldb_module_get_private(module),
		struct descriptor_data);
	struct descriptor_transaction *t = &descriptor_private->transaction;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct descriptor_changes *c, *n;
	int ret;

	DBG_NOTICE("changes: num_registrations=%zu\n",
		   t->changes.num_registrations);
	DBG_NOTICE("changes: num_registered=%zu\n",
		   t->changes.num_registered);

	 
	for (c = t->changes.list; c; c = n) {
		struct descriptor_changes *pc = NULL;
		n = c->next;

		if (c->sort_count >= t->changes.num_registered) {
			 
			break;
		}

		 
		if (!GUID_all_zero((const void*)&c->parent_guid)) {
			TDB_DATA pkey;
			NTSTATUS status;

			pkey = make_tdb_data((const void*)&c->parent_guid,
					     sizeof(c->parent_guid));

			status = dbwrap_parse_record(t->changes.map, pkey,
						     descriptor_changes_parser, &pc);
			if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
				pc = NULL;
				status = NT_STATUS_OK;
			}
			if (!NT_STATUS_IS_OK(status)) {
				ldb_debug(ldb, LDB_DEBUG_FATAL,
					  "dbwrap_parse_record() - %s\n",
					  nt_errstr(status));
				return ldb_module_operr(module);
			}
		}

		if (pc == NULL) {
			 
			t->changes.num_toplevel += 1;
			continue;
		}

		 
		DLIST_REMOVE(t->changes.list, c);
		DLIST_ADD_AFTER(t->changes.list, c, pc);

		 
		c->sort_count += 1;
	}

	DBG_NOTICE("changes: num_toplevel=%zu\n", t->changes.num_toplevel);

	while (t->changes.list != NULL) {
		c = t->changes.list;

		DLIST_REMOVE(t->changes.list, c);

		 
		ret = descriptor_sd_propagation_recursive(module, c);
		if (ret == LDB_ERR_NO_SUCH_OBJECT) {
			continue;
		}
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	DBG_NOTICE("changes: num_processed=%zu\n", t->changes.num_processed);
	DBG_NOTICE("objects: num_processed=%zu\n", t->objects.num_processed);
	DBG_NOTICE("objects: num_skipped=%zu\n", t->objects.num_skipped);

	return ldb_next_prepare_commit(module);
}