tree data UPDATE better support for inline schema mount data

Refs sysrepo/sysrepo#2765
diff --git a/src/tree_data.c b/src/tree_data.c
index b3ca15d..328af88 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -2414,13 +2414,11 @@
 
     assert(new_node);
 
-    if (!first_sibling || !new_node->schema) {
+    if (!first_sibling || !new_node->schema || (LYD_CTX(first_sibling) != LYD_CTX(new_node))) {
         /* insert at the end, no next anchor */
         return NULL;
     }
 
-    assert(!first_sibling || (LYD_CTX(first_sibling) == LYD_CTX(new_node)));
-
     getnext_opts = 0;
     if (new_node->schema->flags & LYS_IS_OUTPUT) {
         getnext_opts = LYS_GETNEXT_OUTPUT;
@@ -2640,7 +2638,7 @@
     /* get first sibling */
     first_sibling = parent ? lyd_child(parent) : *first_sibling_p;
 
-    if (last) {
+    if (last || (first_sibling && (first_sibling->flags & LYD_EXT))) {
         /* no next anchor */
         anchor = NULL;
     } else {
@@ -3490,11 +3488,11 @@
  * @return LY_RRR value.
  */
 static LY_ERR
-lyd_dup_find_schema(const struct lysc_node *schema, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
+lyd_dup_find_schema(const struct lysc_node *schema, const struct ly_ctx *trg_ctx, const struct lyd_node *parent,
         const struct lysc_node **trg_schema)
 {
-    const struct lysc_node *node = NULL, *sparent = NULL;
-    const struct lys_module *mod = NULL;
+    const struct lysc_node *src_parent = NULL, *trg_parent = NULL, *sp, *tp;
+    const struct lys_module *trg_mod = NULL;
     char *path;
 
     if (!schema) {
@@ -3503,32 +3501,52 @@
         return LY_SUCCESS;
     }
 
-    if (parent && parent->schema) {
+    if (lysc_data_parent(schema) && parent && parent->schema) {
         /* start from schema parent */
-        sparent = parent->schema;
-    } else {
-        /* start from module */
-        mod = ly_ctx_get_module_implemented(trg_ctx, schema->module->name);
-        if (!mod) {
-            LOGERR(trg_ctx, LY_ENOTFOUND, "Module \"%s\" not present/implemented in the target context.",
-                    schema->module->name);
+        trg_parent = parent->schema;
+        src_parent = lysc_data_parent(schema);
+    }
+
+    do {
+        /* find the next parent */
+        sp = schema;
+        while (sp->parent != src_parent) {
+            sp = sp->parent;
+        }
+        src_parent = sp;
+
+        if (!src_parent->parent) {
+            /* find the module first */
+            trg_mod = ly_ctx_get_module_implemented(trg_ctx, src_parent->module->name);
+            if (!trg_mod) {
+                LOGERR(trg_ctx, LY_ENOTFOUND, "Module \"%s\" not present/implemented in the target context.",
+                        src_parent->module->name);
+                return LY_ENOTFOUND;
+            }
+        }
+
+        /* find the next parent */
+        assert(trg_parent || trg_mod);
+        tp = NULL;
+        while ((tp = lys_getnext(tp, trg_parent, trg_mod ? trg_mod->compiled : NULL, 0))) {
+            if (!strcmp(tp->name, src_parent->name) && !strcmp(tp->module->name, src_parent->module->name)) {
+                break;
+            }
+        }
+        if (!tp) {
+            /* schema node not found */
+            path = lysc_path(src_parent, LYSC_PATH_LOG, NULL, 0);
+            LOGERR(trg_ctx, LY_ENOTFOUND, "Schema node \"%s\" not found in the target context.", path);
+            free(path);
             return LY_ENOTFOUND;
         }
-    }
 
-    /* find the schema node */
-    while ((node = lys_getnext(node, sparent, mod ? mod->compiled : NULL, 0))) {
-        if (!strcmp(node->module->name, schema->module->name) && !strcmp(node->name, schema->name)) {
-            *trg_schema = node;
-            return LY_SUCCESS;
-        }
-    }
+        trg_parent = tp;
+    } while (schema != src_parent);
 
-    /* schema node not found */
-    path = lysc_path(schema, LYSC_PATH_LOG, NULL, 0);
-    LOGERR(trg_ctx, LY_ENOTFOUND, "Schema node \"%s\" not found in the target context.", path);
-    free(path);
-    return LY_ENOTFOUND;
+    /* success */
+    *trg_schema = trg_parent;
+    return LY_SUCCESS;
 }
 
 /**
@@ -3673,20 +3691,8 @@
             }
         } else if ((dup->schema->nodetype == LYS_LIST) && !(dup->schema->flags & LYS_KEYLESS)) {
             /* always duplicate keys of a list */
-            child = orig->child;
-            for (const struct lysc_node *key = lysc_node_child(dup->schema);
-                    key && (key->flags & LYS_KEY);
-                    key = key->next) {
-                if (!child) {
-                    /* possibly not keys are present in filtered tree */
-                    break;
-                } else if (child->schema != key) {
-                    /* possibly not all keys are present in filtered tree,
-                     * but there can be also some non-key nodes */
-                    continue;
-                }
+            for (child = orig->child; child && lysc_is_key(child->schema); child = child->next) {
                 LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
-                child = child->next;
             }
         }
         lyd_hash(dup);
@@ -4358,16 +4364,28 @@
 LIBYANG_API_DEF LY_ERR
 lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
 {
-    struct lyd_node **match_p, *iter;
+    struct lyd_node **match_p, *iter, *dup = NULL;
     struct lyd_node_inner *parent;
     ly_bool found;
 
     LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
-    LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
+    if (!siblings) {
+        /* no data */
+        if (match) {
+            *match = NULL;
+        }
+        return LY_ENOTFOUND;
+    }
 
-    if (!siblings || (siblings->schema && target->schema &&
-            (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema)))) {
-        /* no data or schema mismatch */
+    if (LYD_CTX(siblings) != LYD_CTX(target)) {
+        /* create a duplicate in this context */
+        LY_CHECK_RET(lyd_dup_single_to_ctx(target, LYD_CTX(siblings), NULL, 0, &dup));
+        target = dup;
+    }
+
+    if ((siblings->schema && target->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema)))) {
+        /* schema mismatch */
+        lyd_free_tree(dup);
         if (match) {
             *match = NULL;
         }
@@ -4413,6 +4431,7 @@
         }
     }
 
+    lyd_free_tree(dup);
     if (!siblings) {
         if (match) {
             *match = NULL;
@@ -4529,12 +4548,25 @@
 {
     LY_ERR rc;
     struct lyd_node *target = NULL;
+    const struct lyd_node *parent;
 
     LY_CHECK_ARG_RET(NULL, schema, !(schema->nodetype & (LYS_CHOICE | LYS_CASE)), LY_EINVAL);
-    LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, schema->module->ctx, LY_EINVAL);
+    if (!siblings) {
+        /* no data */
+        if (match) {
+            *match = NULL;
+        }
+        return LY_ENOTFOUND;
+    }
 
-    if (!siblings || (siblings->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(schema)))) {
-        /* no data or schema mismatch */
+    if ((LYD_CTX(siblings) != schema->module->ctx)) {
+        /* parent of ext nodes is useless */
+        parent = (siblings->flags & LYD_EXT) ? NULL : lyd_parent(siblings);
+        LY_CHECK_RET(lyd_dup_find_schema(schema, LYD_CTX(siblings), parent, &schema));
+    }
+
+    if (siblings->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(schema))) {
+        /* schema mismatch */
         if (match) {
             *match = NULL;
         }