"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/diff.c" (4 Sep 2020, 17102 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "diff.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <inttypes.h>
   15 #include <stdbool.h>
   16 #include <stdlib.h>
   17 
   18 #include <isc/buffer.h>
   19 #include <isc/file.h>
   20 #include <isc/mem.h>
   21 #include <isc/print.h>
   22 #include <isc/string.h>
   23 #include <isc/util.h>
   24 
   25 #include <dns/db.h>
   26 #include <dns/diff.h>
   27 #include <dns/log.h>
   28 #include <dns/rdataclass.h>
   29 #include <dns/rdatalist.h>
   30 #include <dns/rdataset.h>
   31 #include <dns/rdatastruct.h>
   32 #include <dns/rdatatype.h>
   33 #include <dns/result.h>
   34 #include <dns/time.h>
   35 
   36 #define CHECK(op)                            \
   37     do {                                 \
   38         result = (op);               \
   39         if (result != ISC_R_SUCCESS) \
   40             goto failure;        \
   41     } while (0)
   42 
   43 #define DIFF_COMMON_LOGARGS \
   44     dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DIFF
   45 
   46 static dns_rdatatype_t
   47 rdata_covers(dns_rdata_t *rdata) {
   48     return (rdata->type == dns_rdatatype_rrsig ? dns_rdata_covers(rdata)
   49                            : 0);
   50 }
   51 
   52 isc_result_t
   53 dns_difftuple_create(isc_mem_t *mctx, dns_diffop_t op, const dns_name_t *name,
   54              dns_ttl_t ttl, dns_rdata_t *rdata, dns_difftuple_t **tp) {
   55     dns_difftuple_t *t;
   56     unsigned int size;
   57     unsigned char *datap;
   58 
   59     REQUIRE(tp != NULL && *tp == NULL);
   60 
   61     /*
   62      * Create a new tuple.  The variable-size wire-format name data and
   63      * rdata immediately follow the dns_difftuple_t structure
   64      * in memory.
   65      */
   66     size = sizeof(*t) + name->length + rdata->length;
   67     t = isc_mem_allocate(mctx, size);
   68     t->mctx = NULL;
   69     isc_mem_attach(mctx, &t->mctx);
   70     t->op = op;
   71 
   72     datap = (unsigned char *)(t + 1);
   73 
   74     memmove(datap, name->ndata, name->length);
   75     dns_name_init(&t->name, NULL);
   76     dns_name_clone(name, &t->name);
   77     t->name.ndata = datap;
   78     datap += name->length;
   79 
   80     t->ttl = ttl;
   81 
   82     dns_rdata_init(&t->rdata);
   83     dns_rdata_clone(rdata, &t->rdata);
   84     if (rdata->data != NULL) {
   85         memmove(datap, rdata->data, rdata->length);
   86         t->rdata.data = datap;
   87         datap += rdata->length;
   88     } else {
   89         t->rdata.data = NULL;
   90         INSIST(rdata->length == 0);
   91     }
   92 
   93     ISC_LINK_INIT(&t->rdata, link);
   94     ISC_LINK_INIT(t, link);
   95     t->magic = DNS_DIFFTUPLE_MAGIC;
   96 
   97     INSIST(datap == (unsigned char *)t + size);
   98 
   99     *tp = t;
  100     return (ISC_R_SUCCESS);
  101 }
  102 
  103 void
  104 dns_difftuple_free(dns_difftuple_t **tp) {
  105     dns_difftuple_t *t = *tp;
  106     *tp = NULL;
  107     isc_mem_t *mctx;
  108 
  109     REQUIRE(DNS_DIFFTUPLE_VALID(t));
  110 
  111     dns_name_invalidate(&t->name);
  112     t->magic = 0;
  113     mctx = t->mctx;
  114     isc_mem_free(mctx, t);
  115     isc_mem_detach(&mctx);
  116 }
  117 
  118 isc_result_t
  119 dns_difftuple_copy(dns_difftuple_t *orig, dns_difftuple_t **copyp) {
  120     return (dns_difftuple_create(orig->mctx, orig->op, &orig->name,
  121                      orig->ttl, &orig->rdata, copyp));
  122 }
  123 
  124 void
  125 dns_diff_init(isc_mem_t *mctx, dns_diff_t *diff) {
  126     diff->mctx = mctx;
  127     ISC_LIST_INIT(diff->tuples);
  128     diff->magic = DNS_DIFF_MAGIC;
  129 }
  130 
  131 void
  132 dns_diff_clear(dns_diff_t *diff) {
  133     dns_difftuple_t *t;
  134     REQUIRE(DNS_DIFF_VALID(diff));
  135     while ((t = ISC_LIST_HEAD(diff->tuples)) != NULL) {
  136         ISC_LIST_UNLINK(diff->tuples, t, link);
  137         dns_difftuple_free(&t);
  138     }
  139     ENSURE(ISC_LIST_EMPTY(diff->tuples));
  140 }
  141 
  142 void
  143 dns_diff_append(dns_diff_t *diff, dns_difftuple_t **tuplep) {
  144     ISC_LIST_APPEND(diff->tuples, *tuplep, link);
  145     *tuplep = NULL;
  146 }
  147 
  148 /* XXX this is O(N) */
  149 
  150 void
  151 dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep) {
  152     dns_difftuple_t *ot, *next_ot;
  153 
  154     REQUIRE(DNS_DIFF_VALID(diff));
  155     REQUIRE(DNS_DIFFTUPLE_VALID(*tuplep));
  156 
  157     /*
  158      * Look for an existing tuple with the same owner name,
  159      * rdata, and TTL.   If we are doing an addition and find a
  160      * deletion or vice versa, remove both the old and the
  161      * new tuple since they cancel each other out (assuming
  162      * that we never delete nonexistent data or add existing
  163      * data).
  164      *
  165      * If we find an old update of the same kind as
  166      * the one we are doing, there must be a programming
  167      * error.  We report it but try to continue anyway.
  168      */
  169     for (ot = ISC_LIST_HEAD(diff->tuples); ot != NULL; ot = next_ot) {
  170         next_ot = ISC_LIST_NEXT(ot, link);
  171         if (dns_name_caseequal(&ot->name, &(*tuplep)->name) &&
  172             dns_rdata_compare(&ot->rdata, &(*tuplep)->rdata) == 0 &&
  173             ot->ttl == (*tuplep)->ttl)
  174         {
  175             ISC_LIST_UNLINK(diff->tuples, ot, link);
  176             if ((*tuplep)->op == ot->op) {
  177                 UNEXPECTED_ERROR(__FILE__, __LINE__,
  178                          "unexpected non-minimal diff");
  179             } else {
  180                 dns_difftuple_free(tuplep);
  181             }
  182             dns_difftuple_free(&ot);
  183             break;
  184         }
  185     }
  186 
  187     if (*tuplep != NULL) {
  188         ISC_LIST_APPEND(diff->tuples, *tuplep, link);
  189         *tuplep = NULL;
  190     }
  191 }
  192 
  193 static isc_stdtime_t
  194 setresign(dns_rdataset_t *modified) {
  195     dns_rdata_t rdata = DNS_RDATA_INIT;
  196     dns_rdata_rrsig_t sig;
  197     int64_t when;
  198     isc_result_t result;
  199 
  200     result = dns_rdataset_first(modified);
  201     INSIST(result == ISC_R_SUCCESS);
  202     dns_rdataset_current(modified, &rdata);
  203     (void)dns_rdata_tostruct(&rdata, &sig, NULL);
  204     if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
  205         when = 0;
  206     } else {
  207         when = dns_time64_from32(sig.timeexpire);
  208     }
  209     dns_rdata_reset(&rdata);
  210 
  211     result = dns_rdataset_next(modified);
  212     while (result == ISC_R_SUCCESS) {
  213         dns_rdataset_current(modified, &rdata);
  214         (void)dns_rdata_tostruct(&rdata, &sig, NULL);
  215         if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
  216             goto next_rr;
  217         }
  218         if (when == 0 || dns_time64_from32(sig.timeexpire) < when) {
  219             when = dns_time64_from32(sig.timeexpire);
  220         }
  221     next_rr:
  222         dns_rdata_reset(&rdata);
  223         result = dns_rdataset_next(modified);
  224     }
  225     INSIST(result == ISC_R_NOMORE);
  226     return ((isc_stdtime_t)when);
  227 }
  228 
  229 static void
  230 getownercase(dns_rdataset_t *rdataset, dns_name_t *name) {
  231     if (dns_rdataset_isassociated(rdataset)) {
  232         dns_rdataset_getownercase(rdataset, name);
  233     }
  234 }
  235 
  236 static void
  237 setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
  238     if (dns_rdataset_isassociated(rdataset)) {
  239         dns_rdataset_setownercase(rdataset, name);
  240     }
  241 }
  242 
  243 static isc_result_t
  244 diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, bool warn) {
  245     dns_difftuple_t *t;
  246     dns_dbnode_t *node = NULL;
  247     isc_result_t result;
  248     char namebuf[DNS_NAME_FORMATSIZE];
  249     char typebuf[DNS_RDATATYPE_FORMATSIZE];
  250     char classbuf[DNS_RDATACLASS_FORMATSIZE];
  251 
  252     REQUIRE(DNS_DIFF_VALID(diff));
  253     REQUIRE(DNS_DB_VALID(db));
  254 
  255     t = ISC_LIST_HEAD(diff->tuples);
  256     while (t != NULL) {
  257         dns_name_t *name;
  258 
  259         INSIST(node == NULL);
  260         name = &t->name;
  261         /*
  262          * Find the node.
  263          * We create the node if it does not exist.
  264          * This will cause an empty node to be created if the diff
  265          * contains a deletion of an RR at a nonexistent name,
  266          * but such diffs should never be created in the first
  267          * place.
  268          */
  269 
  270         while (t != NULL && dns_name_equal(&t->name, name)) {
  271             dns_rdatatype_t type, covers;
  272             dns_diffop_t op;
  273             dns_rdatalist_t rdl;
  274             dns_rdataset_t rds;
  275             dns_rdataset_t ardataset;
  276             unsigned int options;
  277 
  278             op = t->op;
  279             type = t->rdata.type;
  280             covers = rdata_covers(&t->rdata);
  281 
  282             /*
  283              * Collect a contiguous set of updates with
  284              * the same operation (add/delete) and RR type
  285              * into a single rdatalist so that the
  286              * database rrset merging/subtraction code
  287              * can work more efficiently than if each
  288              * RR were merged into / subtracted from
  289              * the database separately.
  290              *
  291              * This is done by linking rdata structures from the
  292              * diff into "rdatalist".  This uses the rdata link
  293              * field, not the diff link field, so the structure
  294              * of the diff itself is not affected.
  295              */
  296 
  297             dns_rdatalist_init(&rdl);
  298             rdl.type = type;
  299             rdl.covers = covers;
  300             rdl.rdclass = t->rdata.rdclass;
  301             rdl.ttl = t->ttl;
  302 
  303             node = NULL;
  304             if (type != dns_rdatatype_nsec3 &&
  305                 covers != dns_rdatatype_nsec3) {
  306                 CHECK(dns_db_findnode(db, name, true, &node));
  307             } else {
  308                 CHECK(dns_db_findnsec3node(db, name, true,
  309                                &node));
  310             }
  311 
  312             while (t != NULL && dns_name_equal(&t->name, name) &&
  313                    t->op == op && t->rdata.type == type &&
  314                    rdata_covers(&t->rdata) == covers)
  315             {
  316                 /*
  317                  * Remember the add name for
  318                  * dns_rdataset_setownercase.
  319                  */
  320                 name = &t->name;
  321                 if (t->ttl != rdl.ttl && warn) {
  322                     dns_name_format(name, namebuf,
  323                             sizeof(namebuf));
  324                     dns_rdatatype_format(t->rdata.type,
  325                                  typebuf,
  326                                  sizeof(typebuf));
  327                     dns_rdataclass_format(t->rdata.rdclass,
  328                                   classbuf,
  329                                   sizeof(classbuf));
  330                     isc_log_write(DIFF_COMMON_LOGARGS,
  331                               ISC_LOG_WARNING,
  332                               "'%s/%s/%s': TTL differs "
  333                               "in "
  334                               "rdataset, adjusting "
  335                               "%lu -> %lu",
  336                               namebuf, typebuf,
  337                               classbuf,
  338                               (unsigned long)t->ttl,
  339                               (unsigned long)rdl.ttl);
  340                 }
  341                 ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
  342                 t = ISC_LIST_NEXT(t, link);
  343             }
  344 
  345             /*
  346              * Convert the rdatalist into a rdataset.
  347              */
  348             dns_rdataset_init(&rds);
  349             dns_rdataset_init(&ardataset);
  350             CHECK(dns_rdatalist_tordataset(&rdl, &rds));
  351             rds.trust = dns_trust_ultimate;
  352 
  353             /*
  354              * Merge the rdataset into the database.
  355              */
  356             switch (op) {
  357             case DNS_DIFFOP_ADD:
  358             case DNS_DIFFOP_ADDRESIGN:
  359                 options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
  360                       DNS_DBADD_EXACTTTL;
  361                 result = dns_db_addrdataset(db, node, ver, 0,
  362                                 &rds, options,
  363                                 &ardataset);
  364                 break;
  365             case DNS_DIFFOP_DEL:
  366             case DNS_DIFFOP_DELRESIGN:
  367                 options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
  368                 result = dns_db_subtractrdataset(db, node, ver,
  369                                  &rds, options,
  370                                  &ardataset);
  371                 break;
  372             default:
  373                 INSIST(0);
  374                 ISC_UNREACHABLE();
  375             }
  376 
  377             if (result == ISC_R_SUCCESS) {
  378                 if (rds.type == dns_rdatatype_rrsig &&
  379                     (op == DNS_DIFFOP_DELRESIGN ||
  380                      op == DNS_DIFFOP_ADDRESIGN))
  381                 {
  382                     isc_stdtime_t resign;
  383                     resign = setresign(&ardataset);
  384                     dns_db_setsigningtime(db, &ardataset,
  385                                   resign);
  386                 }
  387                 if (op == DNS_DIFFOP_ADD ||
  388                     op == DNS_DIFFOP_ADDRESIGN) {
  389                     setownercase(&ardataset, name);
  390                 }
  391                 if (op == DNS_DIFFOP_DEL ||
  392                     op == DNS_DIFFOP_DELRESIGN) {
  393                     getownercase(&ardataset, name);
  394                 }
  395             } else if (result == DNS_R_UNCHANGED) {
  396                 /*
  397                  * This will not happen when executing a
  398                  * dynamic update, because that code will
  399                  * generate strictly minimal diffs.
  400                  * It may happen when receiving an IXFR
  401                  * from a server that is not as careful.
  402                  * Issue a warning and continue.
  403                  */
  404                 if (warn) {
  405                     dns_name_format(dns_db_origin(db),
  406                             namebuf,
  407                             sizeof(namebuf));
  408                     dns_rdataclass_format(dns_db_class(db),
  409                                   classbuf,
  410                                   sizeof(classbuf));
  411                     isc_log_write(DIFF_COMMON_LOGARGS,
  412                               ISC_LOG_WARNING,
  413                               "%s/%s: dns_diff_apply: "
  414                               "update with no effect",
  415                               namebuf, classbuf);
  416                 }
  417                 if (op == DNS_DIFFOP_ADD ||
  418                     op == DNS_DIFFOP_ADDRESIGN) {
  419                     setownercase(&ardataset, name);
  420                 }
  421                 if (op == DNS_DIFFOP_DEL ||
  422                     op == DNS_DIFFOP_DELRESIGN) {
  423                     getownercase(&ardataset, name);
  424                 }
  425             } else if (result == DNS_R_NXRRSET) {
  426                 /*
  427                  * OK.
  428                  */
  429                 if (op == DNS_DIFFOP_DEL ||
  430                     op == DNS_DIFFOP_DELRESIGN) {
  431                     getownercase(&ardataset, name);
  432                 }
  433                 if (dns_rdataset_isassociated(&ardataset)) {
  434                     dns_rdataset_disassociate(&ardataset);
  435                 }
  436             } else {
  437                 if (dns_rdataset_isassociated(&ardataset)) {
  438                     dns_rdataset_disassociate(&ardataset);
  439                 }
  440                 CHECK(result);
  441             }
  442             dns_db_detachnode(db, &node);
  443             if (dns_rdataset_isassociated(&ardataset)) {
  444                 dns_rdataset_disassociate(&ardataset);
  445             }
  446         }
  447     }
  448     return (ISC_R_SUCCESS);
  449 
  450 failure:
  451     if (node != NULL) {
  452         dns_db_detachnode(db, &node);
  453     }
  454     return (result);
  455 }
  456 
  457 isc_result_t
  458 dns_diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
  459     return (diff_apply(diff, db, ver, true));
  460 }
  461 
  462 isc_result_t
  463 dns_diff_applysilently(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
  464     return (diff_apply(diff, db, ver, false));
  465 }
  466 
  467 /* XXX this duplicates lots of code in diff_apply(). */
  468 
  469 isc_result_t
  470 dns_diff_load(dns_diff_t *diff, dns_addrdatasetfunc_t addfunc,
  471           void *add_private) {
  472     dns_difftuple_t *t;
  473     isc_result_t result;
  474 
  475     REQUIRE(DNS_DIFF_VALID(diff));
  476 
  477     t = ISC_LIST_HEAD(diff->tuples);
  478     while (t != NULL) {
  479         dns_name_t *name;
  480 
  481         name = &t->name;
  482         while (t != NULL && dns_name_caseequal(&t->name, name)) {
  483             dns_rdatatype_t type, covers;
  484             dns_diffop_t op;
  485             dns_rdatalist_t rdl;
  486             dns_rdataset_t rds;
  487 
  488             op = t->op;
  489             type = t->rdata.type;
  490             covers = rdata_covers(&t->rdata);
  491 
  492             dns_rdatalist_init(&rdl);
  493             rdl.type = type;
  494             rdl.covers = covers;
  495             rdl.rdclass = t->rdata.rdclass;
  496             rdl.ttl = t->ttl;
  497 
  498             while (t != NULL &&
  499                    dns_name_caseequal(&t->name, name) &&
  500                    t->op == op && t->rdata.type == type &&
  501                    rdata_covers(&t->rdata) == covers)
  502             {
  503                 ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
  504                 t = ISC_LIST_NEXT(t, link);
  505             }
  506 
  507             /*
  508              * Convert the rdatalist into a rdataset.
  509              */
  510             dns_rdataset_init(&rds);
  511             CHECK(dns_rdatalist_tordataset(&rdl, &rds));
  512             rds.trust = dns_trust_ultimate;
  513 
  514             INSIST(op == DNS_DIFFOP_ADD);
  515             result = (*addfunc)(add_private, name, &rds);
  516             if (result == DNS_R_UNCHANGED) {
  517                 isc_log_write(DIFF_COMMON_LOGARGS,
  518                           ISC_LOG_WARNING,
  519                           "dns_diff_load: "
  520                           "update with no effect");
  521             } else if (result == ISC_R_SUCCESS ||
  522                    result == DNS_R_NXRRSET) {
  523                 /*
  524                  * OK.
  525                  */
  526             } else {
  527                 CHECK(result);
  528             }
  529         }
  530     }
  531     result = ISC_R_SUCCESS;
  532 failure:
  533     return (result);
  534 }
  535 
  536 /*
  537  * XXX uses qsort(); a merge sort would be more natural for lists,
  538  * and perhaps safer wrt thread stack overflow.
  539  */
  540 isc_result_t
  541 dns_diff_sort(dns_diff_t *diff, dns_diff_compare_func *compare) {
  542     unsigned int length = 0;
  543     unsigned int i;
  544     dns_difftuple_t **v;
  545     dns_difftuple_t *p;
  546     REQUIRE(DNS_DIFF_VALID(diff));
  547 
  548     for (p = ISC_LIST_HEAD(diff->tuples); p != NULL;
  549          p = ISC_LIST_NEXT(p, link)) {
  550         length++;
  551     }
  552     if (length == 0) {
  553         return (ISC_R_SUCCESS);
  554     }
  555     v = isc_mem_get(diff->mctx, length * sizeof(dns_difftuple_t *));
  556     for (i = 0; i < length; i++) {
  557         p = ISC_LIST_HEAD(diff->tuples);
  558         v[i] = p;
  559         ISC_LIST_UNLINK(diff->tuples, p, link);
  560     }
  561     INSIST(ISC_LIST_HEAD(diff->tuples) == NULL);
  562     qsort(v, length, sizeof(v[0]), compare);
  563     for (i = 0; i < length; i++) {
  564         ISC_LIST_APPEND(diff->tuples, v[i], link);
  565     }
  566     isc_mem_put(diff->mctx, v, length * sizeof(dns_difftuple_t *));
  567     return (ISC_R_SUCCESS);
  568 }
  569 
  570 /*
  571  * Create an rdataset containing the single RR of the given
  572  * tuple.  The caller must allocate the rdata, rdataset and
  573  * an rdatalist structure for it to refer to.
  574  */
  575 
  576 static isc_result_t
  577 diff_tuple_tordataset(dns_difftuple_t *t, dns_rdata_t *rdata,
  578               dns_rdatalist_t *rdl, dns_rdataset_t *rds) {
  579     REQUIRE(DNS_DIFFTUPLE_VALID(t));
  580     REQUIRE(rdl != NULL);
  581     REQUIRE(rds != NULL);
  582 
  583     dns_rdatalist_init(rdl);
  584     rdl->type = t->rdata.type;
  585     rdl->rdclass = t->rdata.rdclass;
  586     rdl->ttl = t->ttl;
  587     dns_rdataset_init(rds);
  588     ISC_LINK_INIT(rdata, link);
  589     dns_rdata_clone(&t->rdata, rdata);
  590     ISC_LIST_APPEND(rdl->rdata, rdata, link);
  591     return (dns_rdatalist_tordataset(rdl, rds));
  592 }
  593 
  594 isc_result_t
  595 dns_diff_print(dns_diff_t *diff, FILE *file) {
  596     isc_result_t result;
  597     dns_difftuple_t *t;
  598     char *mem = NULL;
  599     unsigned int size = 2048;
  600     const char *op = NULL;
  601 
  602     REQUIRE(DNS_DIFF_VALID(diff));
  603 
  604     mem = isc_mem_get(diff->mctx, size);
  605 
  606     for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
  607          t = ISC_LIST_NEXT(t, link)) {
  608         isc_buffer_t buf;
  609         isc_region_t r;
  610 
  611         dns_rdatalist_t rdl;
  612         dns_rdataset_t rds;
  613         dns_rdata_t rd = DNS_RDATA_INIT;
  614 
  615         result = diff_tuple_tordataset(t, &rd, &rdl, &rds);
  616         if (result != ISC_R_SUCCESS) {
  617             UNEXPECTED_ERROR(__FILE__, __LINE__,
  618                      "diff_tuple_tordataset failed: %s",
  619                      dns_result_totext(result));
  620             result = ISC_R_UNEXPECTED;
  621             goto cleanup;
  622         }
  623     again:
  624         isc_buffer_init(&buf, mem, size);
  625         result = dns_rdataset_totext(&rds, &t->name, false, false,
  626                          &buf);
  627 
  628         if (result == ISC_R_NOSPACE) {
  629             isc_mem_put(diff->mctx, mem, size);
  630             size += 1024;
  631             mem = isc_mem_get(diff->mctx, size);
  632             goto again;
  633         }
  634 
  635         if (result != ISC_R_SUCCESS) {
  636             goto cleanup;
  637         }
  638         /*
  639          * Get rid of final newline.
  640          */
  641         INSIST(buf.used >= 1 &&
  642                ((char *)buf.base)[buf.used - 1] == '\n');
  643         buf.used--;
  644 
  645         isc_buffer_usedregion(&buf, &r);
  646         switch (t->op) {
  647         case DNS_DIFFOP_EXISTS:
  648             op = "exists";
  649             break;
  650         case DNS_DIFFOP_ADD:
  651             op = "add";
  652             break;
  653         case DNS_DIFFOP_DEL:
  654             op = "del";
  655             break;
  656         case DNS_DIFFOP_ADDRESIGN:
  657             op = "add re-sign";
  658             break;
  659         case DNS_DIFFOP_DELRESIGN:
  660             op = "del re-sign";
  661             break;
  662         }
  663         if (file != NULL) {
  664             fprintf(file, "%s %.*s\n", op, (int)r.length,
  665                 (char *)r.base);
  666         } else {
  667             isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG(7),
  668                       "%s %.*s", op, (int)r.length,
  669                       (char *)r.base);
  670         }
  671     }
  672     result = ISC_R_SUCCESS;
  673 cleanup:
  674     if (mem != NULL) {
  675         isc_mem_put(diff->mctx, mem, size);
  676     }
  677     return (result);
  678 }