diff FEATURE diff merge defaults flag

Which allows explicit operations on default nodes.
That is allowed in operational datastore.
diff --git a/src/diff.c b/src/diff.c
index 08d100e..0008277 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1189,21 +1189,21 @@
  * @param[in] diff_match Node from the diff.
  * @param[in] cur_op Current operation of the diff node.
  * @param[in] src_diff Current source diff node.
+ * @param[in] options Diff merge options.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_diff_merge_create(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff)
+lyd_diff_merge_create(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff, uint16_t options)
 {
     struct lyd_node *child;
-    const struct lysc_node_leaf *sleaf;
+    const struct lysc_node_leaf *sleaf = NULL;
     uint32_t trg_flags;
 
     switch (cur_op) {
     case LYD_DIFF_OP_DELETE:
-        if (diff_match->schema->nodetype == LYS_LEAF) {
+        if ((options & LYD_DIFF_MERGE_DEFAULTS) && (diff_match->schema->nodetype == LYS_LEAF)) {
+            /* we are dealing with a leaf and are handling default values specially (as explicit nodes) */
             sleaf = (struct lysc_node_leaf *)diff_match->schema;
-        } else {
-            sleaf = NULL;
         }
 
         /* remember current flags */
@@ -1382,12 +1382,13 @@
  * @param[in] diff_parent Current sysrepo diff parent.
  * @param[in] diff_cb Optional diff callback.
  * @param[in] cb_data User data for @p diff_cb.
+ * @param[in] options Diff merge options.
  * @param[in,out] diff Diff root node.
  * @return LY_ERR value.
  */
 static LY_ERR
 lyd_diff_merge_r(const struct lyd_node *src_diff, struct lyd_node *diff_parent, lyd_diff_cb diff_cb, void *cb_data,
-        struct lyd_node **diff)
+        uint16_t options, struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *child, *diff_node = NULL;
@@ -1409,7 +1410,7 @@
             ret = lyd_diff_merge_replace(diff_node, cur_op, src_diff);
             break;
         case LYD_DIFF_OP_CREATE:
-            ret = lyd_diff_merge_create(diff_node, cur_op, src_diff);
+            ret = lyd_diff_merge_create(diff_node, cur_op, src_diff, options);
             break;
         case LYD_DIFF_OP_DELETE:
             ret = lyd_diff_merge_delete(diff_node, cur_op, src_diff);
@@ -1435,7 +1436,7 @@
 
         /* merge src_diff recursively */
         LY_LIST_FOR(lyd_child_no_keys(src_diff), child) {
-            LY_CHECK_RET(lyd_diff_merge_r(child, diff_parent, diff_cb, cb_data, diff));
+            LY_CHECK_RET(lyd_diff_merge_r(child, diff_parent, diff_cb, cb_data, options, diff));
         }
     } else {
         /* add new diff node with all descendants */
@@ -1472,7 +1473,7 @@
 
 API LY_ERR
 lyd_diff_merge_module(struct lyd_node **diff, const struct lyd_node *src_diff, const struct lys_module *mod,
-        lyd_diff_cb diff_cb, void *cb_data)
+        lyd_diff_cb diff_cb, void *cb_data, uint16_t options)
 {
     const struct lyd_node *src_root;
 
@@ -1483,7 +1484,7 @@
         }
 
         /* apply relevant nodes from the diff datatree */
-        LY_CHECK_RET(lyd_diff_merge_r(src_root, NULL, diff_cb, cb_data, diff));
+        LY_CHECK_RET(lyd_diff_merge_r(src_root, NULL, diff_cb, cb_data, options, diff));
     }
 
     return LY_SUCCESS;
@@ -1491,19 +1492,19 @@
 
 API LY_ERR
 lyd_diff_merge_tree(struct lyd_node **diff_first, struct lyd_node *diff_parent, const struct lyd_node *src_sibling,
-        lyd_diff_cb diff_cb, void *cb_data)
+        lyd_diff_cb diff_cb, void *cb_data, uint16_t options)
 {
     if (!src_sibling) {
         return LY_SUCCESS;
     }
 
-    return lyd_diff_merge_r(src_sibling, diff_parent, diff_cb, cb_data, diff_first);
+    return lyd_diff_merge_r(src_sibling, diff_parent, diff_cb, cb_data, options, diff_first);
 }
 
 API LY_ERR
-lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff)
+lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff, uint16_t options)
 {
-    return lyd_diff_merge_module(diff, src_diff, NULL, NULL, NULL);
+    return lyd_diff_merge_module(diff, src_diff, NULL, NULL, NULL, options);
 }
 
 static LY_ERR
diff --git a/src/tree_data.h b/src/tree_data.h
index 1fe05c9..e431940 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -1504,6 +1504,21 @@
 LY_ERR lyd_diff_apply_all(struct lyd_node **data, const struct lyd_node *diff);
 
 /**
+ * @ingroup datatree
+ * @defgroup diffmergeoptions Data diff merge options.
+ *
+ * Various options to change ::lyd_diff_merge_module(), ::lyd_diff_merge_tree(), and ::lyd_diff_merge_all() behavior.
+ *
+ * Default behavior:
+ * - any default nodes are expected to be a result of validation corrections and not explicitly modified.
+ * @{
+ */
+
+#define LYD_DIFF_MERGE_DEFAULTS   0x01 /**< Default nodes in the diffs are treated as possibly explicitly modified. */
+
+/** @} diffoptions */
+
+/**
  * @brief Merge 2 diffs into each other but restrict the operation to one module.
  *
  * The diffs must be possible to be merged, which is guaranteed only if the source diff was
@@ -1521,11 +1536,12 @@
  * @param[in] mod Module, whose diff only to consider, NULL for all modules.
  * @param[in] diff_cb Optional diff callback that will be called for every changed node.
  * @param[in] cb_data Arbitrary callback data.
+ * @param[in] options Bitmask of options flags, see @ref diffmergeoptions.
  * @return LY_SUCCESS on success,
  * @return LY_ERR on error.
  */
 LY_ERR lyd_diff_merge_module(struct lyd_node **diff, const struct lyd_node *src_diff, const struct lys_module *mod,
-        lyd_diff_cb diff_cb, void *cb_data);
+        lyd_diff_cb diff_cb, void *cb_data, uint16_t options);
 
 /**
  * @brief Merge 2 diff trees into each other.
@@ -1535,21 +1551,23 @@
  * @param[in] src_sibling Source diff sibling to merge.
  * @param[in] diff_cb Optional diff callback that will be called for every changed node.
  * @param[in] cb_data Arbitrary callback data.
+ * @param[in] options Bitmask of options flags, see @ref diffmergeoptions.
  * @return LY_SUCCESS on success,
  * @return LY_ERR on error.
  */
 LY_ERR lyd_diff_merge_tree(struct lyd_node **diff_first, struct lyd_node *diff_parent, const struct lyd_node *src_sibling,
-        lyd_diff_cb diff_cb, void *cb_data);
+        lyd_diff_cb diff_cb, void *cb_data, uint16_t options);
 
 /**
  * @brief Merge 2 diffs into each other.
  *
  * @param[in,out] diff Target diff to merge into.
  * @param[in] src_diff Source diff.
+ * @param[in] options Bitmask of options flags, see @ref diffmergeoptions.
  * @return LY_SUCCESS on success,
  * @return LY_ERR on error.
  */
-LY_ERR lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff);
+LY_ERR lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff, uint16_t options);
 
 /**
  * @brief Reverse a diff and make the opposite changes. Meaning change create to delete, delete to create,
diff --git a/src/validation.c b/src/validation.c
index 3eeacb8..a83ac95 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -47,7 +47,7 @@
     LY_CHECK_RET(lyd_diff_add(node, op, NULL, NULL, NULL, NULL, NULL, &new_diff));
 
     /* merge into existing diff */
-    ret = lyd_diff_merge_all(diff, new_diff);
+    ret = lyd_diff_merge_all(diff, new_diff, 0);
 
     lyd_free_tree(new_diff);
     return ret;
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index f179b54..16658a6 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -472,7 +472,7 @@
     assert_string_equal(st->xml1, st->xml2);
 
     /* merge */
-    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
 
     free(st->xml);
     lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -565,7 +565,7 @@
     assert_string_equal(st->xml1, st->xml2);
 
     /* merge */
-    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
 
     free(st->xml);
     lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -653,7 +653,7 @@
     assert_string_equal(st->xml1, st->xml2);
 
     /* merge */
-    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
 
     free(st->xml);
     lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -736,7 +736,7 @@
     assert_string_equal(st->xml1, st->xml2);
 
     /* merge */
-    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
 
     free(st->xml);
     lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -812,7 +812,7 @@
     assert_string_equal(st->xml1, st->xml2);
 
     /* merge */
-    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
 
     free(st->xml);
     lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -890,7 +890,7 @@
     assert_string_equal(st->xml1, st->xml2);
 
     /* merge */
-    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+    assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
 
     free(st->xml);
     lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK);