data tree CHANGE preserve default flags in diff nodes

Both when duplicating nodes or adding metadata.
diff --git a/src/diff.c b/src/diff.c
index c2e3935..3f5f5b4 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -109,7 +109,7 @@
 
     /* duplicate the subtree (and connect to the diff if possible) */
     LY_CHECK_RET(lyd_dup_single(node, (struct lyd_node_inner *)diff_parent,
-            LYD_DUP_RECURSIVE | LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS, &dup));
+            LYD_DUP_RECURSIVE | LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS, &dup));
 
     /* find the first duplicated parent */
     if (!diff_parent) {
@@ -138,35 +138,35 @@
 
     /* add parent operation, if any */
     if (diff_parent && (diff_parent != dup)) {
-        LY_CHECK_RET(lyd_new_meta(diff_parent, yang_mod, "operation", "none", NULL));
+        LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), diff_parent, yang_mod, "operation", "none", 0, NULL));
     }
 
     /* add subtree operation */
-    LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "operation", lyd_diff_op2str(op), NULL));
+    LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), dup, yang_mod, "operation", lyd_diff_op2str(op), 0, NULL));
 
     /* orig-default */
     if (orig_default) {
-        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "orig-default", orig_default, NULL));
+        LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), dup, yang_mod, "orig-default", orig_default, 0, NULL));
     }
 
     /* orig-value */
     if (orig_value) {
-        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "orig-value", orig_value, NULL));
+        LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), dup, yang_mod, "orig-value", orig_value, 0, NULL));
     }
 
     /* key */
     if (key) {
-        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "key", key, NULL));
+        LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), dup, yang_mod, "key", key, 0, NULL));
     }
 
     /* value */
     if (value) {
-        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "value", value, NULL));
+        LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), dup, yang_mod, "value", value, 0, NULL));
     }
 
     /* orig-key */
     if (orig_key) {
-        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "orig-key", orig_key, NULL));
+        LY_CHECK_RET(lyd_new_meta(LYD_CTX(node), dup, yang_mod, "orig-key", orig_key, 0, NULL));
     }
 
     return LY_SUCCESS;
@@ -1062,6 +1062,7 @@
 
 /**
  * @brief Set a specific operation of a node. Delete the previous operation, if any.
+ * Does not change the default flag.
  *
  * @param[in] node Node to change.
  * @param[in] op Operation to set.
@@ -1079,7 +1080,7 @@
         }
     }
 
-    return lyd_new_meta(node, NULL, "yang:operation", lyd_diff_op2str(op), NULL);
+    return lyd_new_meta(LYD_CTX(node), node, NULL, "yang:operation", lyd_diff_op2str(op), 0, NULL);
 }
 
 /**
@@ -1199,6 +1200,7 @@
 {
     struct lyd_node *child;
     const struct lysc_node_leaf *sleaf;
+    uint32_t trg_flags;
 
     switch (cur_op) {
     case LYD_DIFF_OP_DELETE:
@@ -1208,34 +1210,23 @@
             sleaf = NULL;
         }
 
+        /* remember current flags */
+        trg_flags = diff_match->flags;
+
         if (sleaf && sleaf->dflt &&
                 !sleaf->dflt->realtype->plugin->compare(sleaf->dflt, &((struct lyd_node_term *)src_diff)->value)) {
             /* we deleted it, so a default value was in-use, and it matches the created value -> operation NONE */
             LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
-
-            if (diff_match->schema->nodetype & LYD_NODE_TERM) {
-                /* add orig-dflt metadata */
-                LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-default",
-                        diff_match->flags & LYD_DEFAULT ? "true" : "false", NULL));
-            }
         } else if (!lyd_compare_single(diff_match, src_diff, 0)) {
             /* deleted + created -> operation NONE */
             LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
-
-            if (diff_match->schema->nodetype & LYD_NODE_TERM) {
-                /* add orig-dflt metadata */
-                LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-default",
-                        diff_match->flags & LYD_DEFAULT ? "true" : "false", NULL));
-            }
         } else {
-            assert(sleaf);
             /* we deleted it, but it was created with a different value -> operation REPLACE */
             LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_REPLACE));
-        }
 
-        if (lyd_compare_single(diff_match, src_diff, 0)) {
             /* current value is the previous one (meta) */
-            LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-value", LYD_CANON_VALUE(diff_match), NULL));
+            LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), diff_match, NULL, "yang:orig-value",
+                    LYD_CANON_VALUE(diff_match), 0, NULL));
 
             /* update the value itself */
             LY_CHECK_RET(lyd_change_term(diff_match, LYD_CANON_VALUE(src_diff)));
@@ -1283,8 +1274,8 @@
 
         if (diff_match->schema->nodetype & LYD_NODE_TERM) {
             /* add orig-default meta because it is expected */
-            LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-default",
-                    diff_match->flags & LYD_DEFAULT ? "true" : "false", NULL));
+            LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), diff_match, NULL, "yang:orig-default",
+                    diff_match->flags & LYD_DEFAULT ? "true" : "false", 0, NULL));
         } else {
             /* keep operation for all descendants (for now) */
             LY_LIST_FOR(lyd_child_no_keys(diff_match), child) {
@@ -1448,7 +1439,8 @@
         }
     } else {
         /* add new diff node with all descendants */
-        LY_CHECK_RET(lyd_dup_single(src_diff, (struct lyd_node_inner *)diff_parent, LYD_DUP_RECURSIVE, &diff_node));
+        LY_CHECK_RET(lyd_dup_single(src_diff, (struct lyd_node_inner *)diff_parent, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS,
+                &diff_node));
 
         /* insert node into diff if not already */
         if (!diff_parent) {
diff --git a/src/in.c b/src/in.c
index 0a69853..f802010 100644
--- a/src/in.c
+++ b/src/in.c
@@ -439,7 +439,7 @@
     }
 
     LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
-            hints, &incomplete));
+            hints, 0, &incomplete));
 
     if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
         LY_CHECK_RET(ly_set_add(&lydctx->unres_meta_type, *meta, 1, NULL));
diff --git a/src/parser_xml.c b/src/parser_xml.c
index dc899de..e19b86f 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -596,7 +596,7 @@
 
     /* add metadata/attributes */
     if (snode) {
-        lyd_insert_meta(node, meta);
+        lyd_insert_meta(node, meta, 0);
     } else {
         lyd_insert_attr(node, attr);
     }
diff --git a/src/tree_data.c b/src/tree_data.c
index 2706378..2627811 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -961,23 +961,24 @@
 }
 
 API LY_ERR
-lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
-        struct lyd_meta **meta)
+lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys_module *module, const char *name,
+        const char *val_str, ly_bool clear_dflt, struct lyd_meta **meta)
 {
-    struct lyd_meta *ret = NULL;
-    const struct ly_ctx *ctx;
     const char *prefix, *tmp;
     size_t pref_len, name_len;
 
-    LY_CHECK_ARG_RET(NULL, parent, name, module || strchr(name, ':'), LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, ctx, name, module || strchr(name, ':'), parent || meta, LY_EINVAL);
 
-    ctx = LYD_CTX(parent);
+    if (parent && !parent->schema) {
+        LOGERR(ctx, LY_EINVAL, "Cannot add metadata to an opaque node \"%s\".", ((struct lyd_node_opaq *)parent)->name);
+        return LY_EINVAL;
+    }
 
     /* parse the name */
     tmp = name;
     if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
         LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
-        return LY_EVALID;
+        return LY_EINVAL;
     }
 
     /* find the module */
@@ -991,13 +992,11 @@
         val_str = "";
     }
 
-    LY_CHECK_RET(lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, LY_PREF_JSON,
-            NULL, LYD_HINT_DATA, NULL));
+    return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), NULL, LY_PREF_JSON,
+            NULL, LYD_HINT_DATA, clear_dflt, NULL);
+}
 
-    if (meta) {
-        *meta = ret;
     }
-    return LY_SUCCESS;
 }
 
 API LY_ERR
@@ -1157,7 +1156,7 @@
 
     /* parse the new value into a new meta structure */
     LY_CHECK_GOTO(ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str,
-            strlen(val_str), NULL, LY_PREF_JSON, NULL, LYD_HINT_DATA, NULL), cleanup);
+            strlen(val_str), NULL, LY_PREF_JSON, NULL, LYD_HINT_DATA, 0, NULL), cleanup);
 
     /* compare original and new value */
     if (lyd_compare_meta(meta, m2)) {
@@ -2086,7 +2085,7 @@
 }
 
 void
-lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta)
+lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta, ly_bool clear_dflt)
 {
     struct lyd_meta *last, *iter;
 
@@ -2109,7 +2108,7 @@
     }
 
     /* remove default flags from NP containers */
-    while (parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
+    while (clear_dflt && parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
         parent->flags &= ~LYD_DEFAULT;
         parent = (struct lyd_node *)parent->parent;
     }
@@ -2118,7 +2117,7 @@
 LY_ERR
 lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
         size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
-        void *prefix_data, uint32_t hints, ly_bool *incomplete)
+        void *prefix_data, uint32_t hints, ly_bool clear_dflt, ly_bool *incomplete)
 {
     LY_ERR rc;
     struct lysc_ext_instance *ant = NULL;
@@ -2154,7 +2153,7 @@
 
     /* insert as the last attribute */
     if (parent) {
-        lyd_insert_meta(parent, mt);
+        lyd_insert_meta(parent, mt, clear_dflt);
     } else if (*meta) {
         for (last = *meta; last->next; last = last->next) {}
         last->next = mt;
diff --git a/src/tree_data.h b/src/tree_data.h
index 0027364..1fe05c9 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -906,19 +906,21 @@
         LYD_ANYDATA_VALUETYPE value_type, ly_bool output, struct lyd_node **node);
 
 /**
- * @brief Create new metadata for a data node.
+ * @brief Create new metadata.
  *
- * @param[in] parent Parent node for the metadata being created.
+ * @param[in] ctx libyang context,
+ * @param[in] parent Optional parent node for the metadata being created. Must be set if @p meta is NULL.
  * @param[in] module Module of the metadata being created. If NULL, @p name must include module name as the prefix.
  * @param[in] name Annotation name of the new metadata. It can include the annotation module as the prefix.
  *            If the prefix is specified it is always used but if not specified, @p module must be set.
  * @param[in] val_str String form of the value of the metadata. In case of an instance-identifier or identityref
  * value, the JSON format is expected (module names instead of prefixes).
- * @param[out] meta Optional created metadata.
+ * @param[in] clear_dflt Whether to clear the default flag starting from @p parent, recursively all NP containers.
+ * @param[out] meta Optional created metadata. Must be set if @p parent is NULL.
  * @return LY_ERR value.
  */
-LY_ERR lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
-        struct lyd_meta **meta);
+LY_ERR lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys_module *module, const char *name,
+        const char *val_str, ly_bool clear_dflt, struct lyd_meta **meta);
 
 /**
  * @brief Create a new opaque node in the data tree.
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index bc181af..a633873 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -227,8 +227,9 @@
  *
  * @param[in] parent Parent of the metadata.
  * @param[in] meta Metadata (list) to be added into the @p parent.
+ * @param[in] clear_dflt Whether to clear dflt flag starting from @p parent, recursively all NP containers.
  */
-void lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta);
+void lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta, ly_bool clear_dflt);
 
 /**
  * @brief Create and insert a metadata (last) into a parent.
@@ -244,6 +245,7 @@
  * @param[in] format Input format of @p value.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
  * @param[in] hints [Value hints](@ref lydvalhints) from the parser regarding the value type.
+ * @param[in] clear_dflt Whether to clear dflt flag starting from @p parent, recursively all NP containers.
  * @param[out] incomplete Whether the value needs to be resolved.
  * @return LY_SUCCESS on success.
  * @return LY_EINCOMPLETE in case data tree is needed to finish the validation.
@@ -251,7 +253,7 @@
  */
 LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
         size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
-        void *prefix_data, uint32_t hints, ly_bool *incomplete);
+        void *prefix_data, uint32_t hints, ly_bool clear_dlft, ly_bool *incomplete);
 
 /**
  * @brief Insert an attribute (last) into a parent