]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add fr_edit_list_free_children()
authorAlan T. DeKok <aland@freeradius.org>
Sun, 14 Nov 2021 03:07:15 +0000 (22:07 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 14 Nov 2021 03:09:28 +0000 (22:09 -0500)
which will clear the children of a structural type

src/lib/util/edit.c
src/lib/util/edit.h

index bd3be7e9e77ea4d545308aafe280b3c89205bff9..4a91d0e9bae28da2626419c03c59118850ebeb59 100644 (file)
@@ -33,6 +33,7 @@ typedef enum {
        FR_EDIT_INVALID = 0,
        FR_EDIT_DELETE,                 //!< delete a VP
        FR_EDIT_VALUE,                  //!< edit a VP in place
+       FR_EDIT_CLEAR,                  //!< clear the children of a structural entry.
        FR_EDIT_INSERT,                 //!< insert a VP into a list, after another one.
 } fr_edit_op_t;
 
@@ -44,6 +45,7 @@ static const char *edit_names[4] = {
        "invalid",
        "delete",
        "value",
+       "clear",
        "insert",
 };
 #endif
@@ -74,8 +76,7 @@ typedef struct {
 
        union {
                fr_value_box_t  data;   //!< original data
-               fr_pair_list_t  children;  //!< original child list,
-                                          //!< for T_OP_SET of structural entries
+               fr_pair_list_t  children;  //!< original child list, for "clear"
 
                struct {
                        fr_pair_list_t  *list; //!< parent list
@@ -107,6 +108,13 @@ static int edit_undo(fr_edit_t *e)
                fr_value_box_copy_shallow(NULL, &vp->data, &e->data);
                break;
 
+       case FR_EDIT_CLEAR:
+               fr_assert(fr_type_is_structural(vp->vp_type));
+
+               fr_pair_list_free(&vp->vp_group);
+               fr_pair_list_append(&vp->vp_group, &e->children);
+               break;
+
        case FR_EDIT_DELETE:
                fr_assert(e->list != NULL);
 #ifndef NDEBUG
@@ -249,6 +257,26 @@ static int edit_record(fr_edit_list_t *el, fr_edit_op_t op, fr_pair_t *vp, fr_pa
                        fr_assert(0);
                        return -1;
 
+               case FR_EDIT_CLEAR:
+                       /*
+                        *      If we're clearing it, we MUST have
+                        *      previously inserted it.  So just nuke
+                        *      it's children, as merging the
+                        *      operations of "insert with stuff" and
+                        *      then "clear" is just "insert empty
+                        *      pair".
+                        *
+                        *      However, we don't yet delete the
+                        *      children, as there may be other edit
+                        *      operations which are referring to
+                        *      them.
+                        */
+                       fr_assert(e->op == FR_EDIT_INSERT);
+                       fr_assert(fr_type_is_structural(vp->vp_type));
+
+                       fr_pair_list_append(&el->deleted_pairs, &vp->vp_group);
+                       break;
+
                        /*
                         *      We're being asked to delete something
                         *      we previously inserted, or previously
@@ -293,7 +321,6 @@ static int edit_record(fr_edit_list_t *el, fr_edit_op_t op, fr_pair_t *vp, fr_pa
                         *      original one, and then track the
                         *      deletion.
                         */
-                       fr_assert(e->op == FR_EDIT_VALUE);
                        edit_undo(e);
 
                        /*
@@ -338,6 +365,15 @@ static int edit_record(fr_edit_list_t *el, fr_edit_op_t op, fr_pair_t *vp, fr_pa
                                                                                     e->data.tainted);
                break;
 
+       case FR_EDIT_CLEAR:
+               fr_assert(list == NULL);
+               fr_assert(ref == NULL);
+
+               fr_assert(fr_type_is_structural(vp->vp_type));
+               fr_pair_list_init(&e->children);
+               fr_pair_list_append(&e->children, &vp->vp_group);
+               break;
+
        case FR_EDIT_INSERT:
                fr_assert(list != NULL);
 
@@ -464,10 +500,31 @@ int fr_edit_list_replace(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *to
 }
 
 
+/** Replace a pair with another one.
+ *
+ *  This function mirrors fr_pair_replace().
+ *
+ *  After this function returns, the new VP has replaced the old one,
+ *  and the new one can be edited.
+ */
+int fr_edit_list_free_children(fr_edit_list_t *el, fr_pair_t *vp)
+{
+       if (!el) return 0;
+
+       if (!fr_type_is_structural(vp->vp_type)) return -1;
+
+       /*
+        *      Record the list, even if it's empty.  That way if we
+        *      later add children to it, the "undo" operation can
+        *      reset the children list to be empty.
+        */
+       return edit_record(el, FR_EDIT_CLEAR, vp, NULL, NULL);
+}
+
 /** Finalize the edits when we destroy the edit list.
  *
  *  Which in large part means freeing the VPs which have been deleted,
- *  and then deleting the edit list.
+ *  or saved, and then deleting the edit list.
  */
 static int _edit_list_destructor(fr_edit_list_t *el)
 {
@@ -491,6 +548,10 @@ static int _edit_list_destructor(fr_edit_list_t *el)
                        talloc_free(e->vp);
                        break;
 
+               case FR_EDIT_CLEAR:
+                       fr_pair_list_free(&e->children);
+                       break;
+
                case FR_EDIT_VALUE:
                        fr_assert(fr_type_is_leaf(e->vp->vp_type));
                        fr_value_box_clear(&e->data);
index e9fc463a8bd6b0d54f2eef26c17e7816474ffcbd..b8917de626db776f7935e3690ff179d2bb4acf6a 100644 (file)
@@ -49,6 +49,8 @@ int fr_edit_list_replace_value(fr_edit_list_t *el, fr_pair_t *vp, fr_value_box_t
 
 int fr_edit_list_replace(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *to_replace, fr_pair_t *vp) CC_HINT(nonnull(2,3,4));
 
+int fr_edit_list_free_children(fr_edit_list_t *el, fr_pair_t *vp) CC_HINT(nonnull(2));
+
 #ifdef __cplusplus
 }
 #endif