]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/dns/rdataslab.c
This commit was generated by cvs2svn to compensate for changes in r172423,
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / dns / rdataslab.c
1 /*
2  * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: rdataslab.c,v 1.35.18.5 2006/03/05 23:58:51 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25
26 #include <isc/mem.h>
27 #include <isc/region.h>
28 #include <isc/string.h>         /* Required for HP/UX (and others?) */
29 #include <isc/util.h>
30
31 #include <dns/result.h>
32 #include <dns/rdata.h>
33 #include <dns/rdataset.h>
34 #include <dns/rdataslab.h>
35
36 /*
37  * The rdataslab structure allows iteration to occur in both load order
38  * and DNSSEC order.  The structure is as follows:
39  *
40  *      header          (reservelen bytes)
41  *      record count    (2 bytes)
42  *      offset table    (4 x record count bytes in load order)
43  *      data records
44  *              data length     (2 bytes)
45  *              order           (2 bytes)
46  *              data            (data length bytes)
47  *
48  * Offsets are from the end of the header.
49  *
50  * Load order traversal is performed by walking the offset table to find
51  * the start of the record.
52  *
53  * DNSSEC order traversal is performed by walking the data records.
54  *
55  * The order is stored with record to allow for efficient reconstuction of
56  * of the offset table following a merge or subtraction.
57  *
58  * The iterator methods here currently only support DNSSEC order iteration.
59  *
60  * The iterator methods in rbtdb support both load order and DNSSEC order
61  * iteration.
62  *
63  * WARNING:
64  *      rbtdb.c directly interacts with the slab's raw structures.  If the
65  *      structure changes then rbtdb.c also needs to be updated to reflect
66  *      the changes.  See the areas tagged with "RDATASLAB".
67  */
68
69 struct xrdata {
70         dns_rdata_t     rdata;
71         unsigned int    order;
72 };
73
74 /*% Note: the "const void *" are just to make qsort happy.  */
75 static int
76 compare_rdata(const void *p1, const void *p2) {
77         const struct xrdata *x1 = p1;
78         const struct xrdata *x2 = p2;
79         return (dns_rdata_compare(&x1->rdata, &x2->rdata));
80 }
81
82 static void
83 fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
84                unsigned length)
85 {
86         unsigned int i, j;
87         unsigned char *raw;
88
89         for (i = 0, j = 0; i < length; i++) {
90
91                 if (offsettable[i] == 0)
92                         continue;
93
94                 /*
95                  * Fill in offset table.
96                  */
97                 raw = &offsetbase[j*4 + 2];
98                 *raw++ = (offsettable[i] & 0xff000000) >> 24;
99                 *raw++ = (offsettable[i] & 0xff0000) >> 16;
100                 *raw++ = (offsettable[i] & 0xff00) >> 8;
101                 *raw = offsettable[i] & 0xff;
102
103                 /*
104                  * Fill in table index.
105                  */
106                 raw = offsetbase + offsettable[i] + 2;
107                 *raw++ = (j & 0xff00) >> 8;
108                 *raw = j++ & 0xff;
109         }
110 }
111
112 isc_result_t
113 dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
114                            isc_region_t *region, unsigned int reservelen)
115 {
116         struct xrdata  *x;
117         unsigned char  *rawbuf;
118         unsigned char  *offsetbase;
119         unsigned int    buflen;
120         isc_result_t    result;
121         unsigned int    nitems;
122         unsigned int    nalloc;
123         unsigned int    i;
124         unsigned int   *offsettable;
125
126         buflen = reservelen + 2;
127
128         nalloc = dns_rdataset_count(rdataset);
129         nitems = nalloc;
130         if (nitems == 0)
131                 return (ISC_R_FAILURE);
132
133         if (nalloc > 0xffff)
134                 return (ISC_R_NOSPACE);
135
136         x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata));
137         if (x == NULL)
138                 return (ISC_R_NOMEMORY);
139
140         /*
141          * Save all of the rdata members into an array.
142          */
143         result = dns_rdataset_first(rdataset);
144         if (result != ISC_R_SUCCESS)
145                 goto free_rdatas;
146         for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
147                 INSIST(result == ISC_R_SUCCESS);
148                 dns_rdata_init(&x[i].rdata);
149                 dns_rdataset_current(rdataset, &x[i].rdata);
150                 x[i].order = i;
151                 result = dns_rdataset_next(rdataset);
152         }
153         if (result != ISC_R_NOMORE)
154                 goto free_rdatas;
155         if (i != nalloc) {
156                 /*
157                  * Somehow we iterated over fewer rdatas than
158                  * dns_rdataset_count() said there were!
159                  */
160                 result = ISC_R_FAILURE;
161                 goto free_rdatas;
162         }
163
164         /*
165          * Put into DNSSEC order.
166          */
167         qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);
168
169         /*
170          * Remove duplicates and compute the total storage required.
171          *
172          * If an rdata is not a duplicate, accumulate the storage size
173          * required for the rdata.  We do not store the class, type, etc,
174          * just the rdata, so our overhead is 2 bytes for the number of
175          * records, and 8 for each rdata, (length(2), offset(4) and order(2))
176          * and then the rdata itself.
177          */
178         for (i = 1; i < nalloc; i++) {
179                 if (compare_rdata(&x[i-1].rdata, &x[i].rdata) == 0) {
180                         x[i-1].rdata.data = NULL;
181                         x[i-1].rdata.length = 0;
182                         /*
183                          * Preserve the least order so A, B, A -> A, B
184                          * after duplicate removal.
185                          */
186                         if (x[i-1].order < x[i].order)
187                                 x[i].order = x[i-1].order;
188                         nitems--;
189                 } else
190                         buflen += (8 + x[i-1].rdata.length);
191         }
192         /*
193          * Don't forget the last item!
194          */
195         buflen += (8 + x[i-1].rdata.length);
196
197         /*
198          * Ensure that singleton types are actually singletons.
199          */
200         if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
201                 /*
202                  * We have a singleton type, but there's more than one
203                  * RR in the rdataset.
204                  */
205                 result = DNS_R_SINGLETON;
206                 goto free_rdatas;
207         }
208
209         /*
210          * Allocate the memory, set up a buffer, start copying in
211          * data.
212          */
213         rawbuf = isc_mem_get(mctx, buflen);
214         if (rawbuf == NULL) {
215                 result = ISC_R_NOMEMORY;
216                 goto free_rdatas;
217         }
218         
219         /* Allocate temporary offset table. */
220         offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int));
221         if (offsettable == NULL) {
222                 isc_mem_put(mctx, rawbuf, buflen);
223                 result = ISC_R_NOMEMORY;
224                 goto free_rdatas;
225         }
226         memset(offsettable, 0, nalloc * sizeof(unsigned int));
227
228         region->base = rawbuf;
229         region->length = buflen;
230
231         rawbuf += reservelen;
232         offsetbase = rawbuf;
233
234         *rawbuf++ = (nitems & 0xff00) >> 8;
235         *rawbuf++ = (nitems & 0x00ff);
236
237         /* Skip load order table.  Filled in later. */
238         rawbuf += nitems * 4;
239
240         for (i = 0; i < nalloc; i++) {
241                 if (x[i].rdata.data == NULL)
242                         continue;
243                 offsettable[x[i].order] = rawbuf - offsetbase;
244                 *rawbuf++ = (x[i].rdata.length & 0xff00) >> 8;
245                 *rawbuf++ = (x[i].rdata.length & 0x00ff);
246                 rawbuf += 2;    /* filled in later */
247                 memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length);
248                 rawbuf += x[i].rdata.length;
249         }
250         
251         fillin_offsets(offsetbase, offsettable, nalloc);
252
253         isc_mem_put(mctx, offsettable, nalloc * sizeof(unsigned int));
254
255         result = ISC_R_SUCCESS;
256
257  free_rdatas:
258         isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
259         return (result);
260 }
261
262 static void
263 rdataset_disassociate(dns_rdataset_t *rdataset) {
264         UNUSED(rdataset);
265 }
266
267 static isc_result_t
268 rdataset_first(dns_rdataset_t *rdataset) {
269         unsigned char *raw = rdataset->private3;
270         unsigned int count;
271
272         count = raw[0] * 256 + raw[1];
273         if (count == 0) {
274                 rdataset->private5 = NULL;
275                 return (ISC_R_NOMORE);
276         }
277         raw += 2 + (4 * count);
278         /*
279          * The privateuint4 field is the number of rdata beyond the cursor
280          * position, so we decrement the total count by one before storing
281          * it.
282          */
283         count--;
284         rdataset->privateuint4 = count;
285         rdataset->private5 = raw;
286
287         return (ISC_R_SUCCESS);
288 }
289
290 static isc_result_t
291 rdataset_next(dns_rdataset_t *rdataset) {
292         unsigned int count;
293         unsigned int length;
294         unsigned char *raw;
295
296         count = rdataset->privateuint4;
297         if (count == 0)
298                 return (ISC_R_NOMORE);
299         count--;
300         rdataset->privateuint4 = count;
301         raw = rdataset->private5;
302         length = raw[0] * 256 + raw[1];
303         raw += length + 4;
304         rdataset->private5 = raw;
305
306         return (ISC_R_SUCCESS);
307 }
308
309 static void
310 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
311         unsigned char *raw = rdataset->private5;
312         isc_region_t r;
313
314         REQUIRE(raw != NULL);
315
316         r.length = raw[0] * 256 + raw[1];
317         raw += 4;
318         r.base = raw;
319         dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
320 }
321
322 static void
323 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
324         *target = *source;
325
326         /*
327          * Reset iterator state.
328          */
329         target->privateuint4 = 0;
330         target->private5 = NULL;
331 }
332
333 static unsigned int
334 rdataset_count(dns_rdataset_t *rdataset) {
335         unsigned char *raw = rdataset->private3;
336         unsigned int count;
337
338         count = raw[0] * 256 + raw[1];
339
340         return (count);
341 }
342
343 static dns_rdatasetmethods_t rdataset_methods = {
344         rdataset_disassociate,
345         rdataset_first,
346         rdataset_next,
347         rdataset_current,
348         rdataset_clone,
349         rdataset_count,
350         NULL,
351         NULL,
352         NULL,
353         NULL,
354         NULL
355 };
356
357 void
358 dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen,
359                          dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
360                          dns_rdatatype_t covers, dns_ttl_t ttl,
361                          dns_rdataset_t *rdataset)
362 {
363         REQUIRE(slab != NULL);
364         REQUIRE(!dns_rdataset_isassociated(rdataset));
365
366         rdataset->methods = &rdataset_methods;
367         rdataset->rdclass = rdclass;
368         rdataset->type = rdtype;
369         rdataset->covers = covers;
370         rdataset->ttl = ttl;
371         rdataset->trust = 0;
372         rdataset->private1 = NULL;
373         rdataset->private2 = NULL;
374         rdataset->private3 = slab + reservelen;
375
376         /*
377          * Reset iterator state.
378          */
379         rdataset->privateuint4 = 0;
380         rdataset->private5 = NULL;
381 }
382
383 unsigned int
384 dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) {
385         unsigned int count, length;
386         unsigned char *current;
387
388         REQUIRE(slab != NULL);
389
390         current = slab + reservelen;
391         count = *current++ * 256;
392         count += *current++;
393         current += (4 * count);
394         while (count > 0) {
395                 count--;
396                 length = *current++ * 256;
397                 length += *current++;
398                 current += length + 2;
399         }
400
401         return ((unsigned int)(current - slab));
402 }
403
404 /*
405  * Make the dns_rdata_t 'rdata' refer to the slab item
406  * beginning at '*current', which is part of a slab of type
407  * 'type' and class 'rdclass', and advance '*current' to
408  * point to the next item in the slab.
409  */
410 static inline void
411 rdata_from_slab(unsigned char **current,
412               dns_rdataclass_t rdclass, dns_rdatatype_t type,
413               dns_rdata_t *rdata)
414 {
415         unsigned char *tcurrent = *current;
416         isc_region_t region;
417
418         region.length = *tcurrent++ * 256;
419         region.length += *tcurrent++;
420         tcurrent += 2;
421         region.base = tcurrent;
422         tcurrent += region.length;
423         dns_rdata_fromregion(rdata, rdclass, type, &region);
424         *current = tcurrent;
425 }
426
427 /*
428  * Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
429  * contains an rdata identical to 'rdata'.  This does case insensitive
430  * comparisons per DNSSEC.
431  */
432 static inline isc_boolean_t
433 rdata_in_slab(unsigned char *slab, unsigned int reservelen,
434               dns_rdataclass_t rdclass, dns_rdatatype_t type,
435               dns_rdata_t *rdata)
436 {
437         unsigned int count, i;
438         unsigned char *current;
439         dns_rdata_t trdata = DNS_RDATA_INIT;
440         int n;
441
442         current = slab + reservelen;
443         count = *current++ * 256;
444         count += *current++;
445
446         current += (4 * count);
447
448         for (i = 0; i < count; i++) {
449                 rdata_from_slab(&current, rdclass, type, &trdata);
450                 
451                 n = dns_rdata_compare(&trdata, rdata);
452                 if (n == 0)
453                         return (ISC_TRUE);
454                 if (n > 0)      /* In DNSSEC order. */
455                         break;
456                 dns_rdata_reset(&trdata);
457         }
458         return (ISC_FALSE);
459 }
460
461 isc_result_t
462 dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
463                     unsigned int reservelen, isc_mem_t *mctx,
464                     dns_rdataclass_t rdclass, dns_rdatatype_t type,
465                     unsigned int flags, unsigned char **tslabp)
466 {
467         unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent;
468         unsigned int ocount, ncount, count, olength, tlength, tcount, length;
469         isc_region_t nregion;
470         dns_rdata_t ordata = DNS_RDATA_INIT;
471         dns_rdata_t nrdata = DNS_RDATA_INIT;
472         isc_boolean_t added_something = ISC_FALSE;
473         unsigned int oadded = 0;
474         unsigned int nadded = 0;
475         unsigned int nncount = 0;
476         unsigned int oncount;
477         unsigned int norder = 0;
478         unsigned int oorder = 0;
479         unsigned char *offsetbase;
480         unsigned int *offsettable;
481
482         /*
483          * XXX  Need parameter to allow "delete rdatasets in nslab" merge,
484          * or perhaps another merge routine for this purpose.
485          */
486
487         REQUIRE(tslabp != NULL && *tslabp == NULL);
488         REQUIRE(oslab != NULL && nslab != NULL);
489
490         ocurrent = oslab + reservelen;
491         ocount = *ocurrent++ * 256;
492         ocount += *ocurrent++;
493         ocurrent += (4 * ocount);
494         ostart = ocurrent;
495         ncurrent = nslab + reservelen;
496         ncount = *ncurrent++ * 256;
497         ncount += *ncurrent++;
498         ncurrent += (4 * ncount);
499         INSIST(ocount > 0 && ncount > 0);
500
501         oncount = ncount;
502
503         /*
504          * Yes, this is inefficient!
505          */
506
507         /*
508          * Figure out the length of the old slab's data.
509          */
510         olength = 0;
511         for (count = 0; count < ocount; count++) {
512                 length = *ocurrent++ * 256;
513                 length += *ocurrent++;
514                 olength += length + 8;
515                 ocurrent += length + 2;
516         }
517
518         /*
519          * Start figuring out the target length and count.
520          */
521         tlength = reservelen + 2 + olength;
522         tcount = ocount;
523
524         /*
525          * Add in the length of rdata in the new slab that aren't in
526          * the old slab.
527          */
528         do {
529                 nregion.length = *ncurrent++ * 256;
530                 nregion.length += *ncurrent++;
531                 ncurrent += 2;
532                 nregion.base = ncurrent;
533                 dns_rdata_init(&nrdata);
534                 dns_rdata_fromregion(&nrdata, rdclass, type, &nregion);
535                 if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata))
536                 {
537                         /*
538                          * This rdata isn't in the old slab.
539                          */
540                         tlength += nregion.length + 8;
541                         tcount++;
542                         nncount++;
543                         added_something = ISC_TRUE;
544                 }
545                 ncurrent += nregion.length;
546                 ncount--;
547         } while (ncount > 0);
548         ncount = nncount;
549
550         if (((flags & DNS_RDATASLAB_EXACT) != 0) &&
551             (tcount != ncount + ocount))
552                 return (DNS_R_NOTEXACT);
553
554         if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0)
555                 return (DNS_R_UNCHANGED);
556
557         /*
558          * Ensure that singleton types are actually singletons.
559          */
560         if (tcount > 1 && dns_rdatatype_issingleton(type)) {
561                 /*
562                  * We have a singleton type, but there's more than one
563                  * RR in the rdataset.
564                  */
565                 return (DNS_R_SINGLETON);
566         }
567
568         if (tcount > 0xffff)
569                 return (ISC_R_NOSPACE);
570
571         /*
572          * Copy the reserved area from the new slab.
573          */
574         tstart = isc_mem_get(mctx, tlength);
575         if (tstart == NULL)
576                 return (ISC_R_NOMEMORY);
577         memcpy(tstart, nslab, reservelen);
578         tcurrent = tstart + reservelen;
579         offsetbase = tcurrent;
580
581         /*
582          * Write the new count.
583          */
584         *tcurrent++ = (tcount & 0xff00) >> 8;
585         *tcurrent++ = (tcount & 0x00ff);
586
587         /*
588          * Skip offset table.
589          */
590         tcurrent += (tcount * 4);
591
592         offsettable = isc_mem_get(mctx,
593                                   (ocount + oncount) * sizeof(unsigned int));
594         if (offsettable == NULL) {
595                 isc_mem_put(mctx, tstart, tlength);
596                 return (ISC_R_NOMEMORY);
597         }
598         memset(offsettable, 0, (ocount + oncount) * sizeof(unsigned int));
599
600         /*
601          * Merge the two slabs.
602          */
603         ocurrent = ostart;
604         INSIST(ocount != 0);
605         oorder = ocurrent[2] * 256 + ocurrent[3];
606         INSIST(oorder < ocount);
607         rdata_from_slab(&ocurrent, rdclass, type, &ordata);
608
609         ncurrent = nslab + reservelen + 2;
610         ncurrent += (4 * oncount);
611
612         if (ncount > 0) {
613                 do {
614                         dns_rdata_reset(&nrdata);
615                         norder = ncurrent[2] * 256 + ncurrent[3];
616                         INSIST(norder < oncount);
617                         rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
618                 } while (rdata_in_slab(oslab, reservelen, rdclass,
619                                        type, &nrdata));
620         }
621
622         while (oadded < ocount || nadded < ncount) {
623                 isc_boolean_t fromold;
624                 if (oadded == ocount)
625                         fromold = ISC_FALSE;
626                 else if (nadded == ncount)
627                         fromold = ISC_TRUE;
628                 else
629                         fromold = ISC_TF(compare_rdata(&ordata, &nrdata) < 0);
630                 if (fromold) {
631                         offsettable[oorder] = tcurrent - offsetbase;
632                         length = ordata.length;
633                         *tcurrent++ = (length & 0xff00) >> 8;
634                         *tcurrent++ = (length & 0x00ff);
635                         tcurrent += 2;  /* fill in later */
636                         memcpy(tcurrent, ordata.data, length);
637                         tcurrent += length;
638                         oadded++;
639                         if (oadded < ocount) {
640                                 dns_rdata_reset(&ordata);
641                                 oorder = ocurrent[2] * 256 + ocurrent[3];
642                                 INSIST(oorder < ocount);
643                                 rdata_from_slab(&ocurrent, rdclass, type,
644                                                 &ordata);
645                         }
646                 } else {
647                         offsettable[ocount + norder] = tcurrent - offsetbase;
648                         length = nrdata.length;
649                         *tcurrent++ = (length & 0xff00) >> 8;
650                         *tcurrent++ = (length & 0x00ff);
651                         tcurrent += 2;  /* fill in later */
652                         memcpy(tcurrent, nrdata.data, length);
653                         tcurrent += length;
654                         nadded++;
655                         if (nadded < ncount) {
656                                 do {
657                                         dns_rdata_reset(&nrdata);
658                                         norder = ncurrent[2] * 256 + ncurrent[3];
659                                         INSIST(norder < oncount);
660                                         rdata_from_slab(&ncurrent, rdclass,
661                                                         type, &nrdata);
662                                 } while (rdata_in_slab(oslab, reservelen,
663                                                        rdclass, type,
664                                                        &nrdata));
665                         }
666                 }
667         }
668
669         fillin_offsets(offsetbase, offsettable, ocount + oncount);
670
671         isc_mem_put(mctx, offsettable,
672                     (ocount + oncount) * sizeof(unsigned int));
673
674         INSIST(tcurrent == tstart + tlength);
675
676         *tslabp = tstart;
677
678         return (ISC_R_SUCCESS);
679 }
680
681 isc_result_t
682 dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
683                        unsigned int reservelen, isc_mem_t *mctx,
684                        dns_rdataclass_t rdclass, dns_rdatatype_t type,
685                        unsigned int flags, unsigned char **tslabp)
686 {
687         unsigned char *mcurrent, *sstart, *scurrent, *tstart, *tcurrent;
688         unsigned int mcount, scount, rcount ,count, tlength, tcount, i;
689         dns_rdata_t srdata = DNS_RDATA_INIT;
690         dns_rdata_t mrdata = DNS_RDATA_INIT;
691         unsigned char *offsetbase;
692         unsigned int *offsettable;
693         unsigned int order;
694
695         REQUIRE(tslabp != NULL && *tslabp == NULL);
696         REQUIRE(mslab != NULL && sslab != NULL);
697
698         mcurrent = mslab + reservelen;
699         mcount = *mcurrent++ * 256;
700         mcount += *mcurrent++;
701         scurrent = sslab + reservelen;
702         scount = *scurrent++ * 256;
703         scount += *scurrent++;
704         INSIST(mcount > 0 && scount > 0);
705
706         /*
707          * Yes, this is inefficient!
708          */
709
710         /*
711          * Start figuring out the target length and count.
712          */
713         tlength = reservelen + 2;
714         tcount = 0;
715         rcount = 0;
716
717         mcurrent += 4 * mcount;
718         scurrent += 4 * scount;
719         sstart = scurrent;
720
721         /*
722          * Add in the length of rdata in the mslab that aren't in
723          * the sslab.
724          */
725         for (i = 0; i < mcount; i++) {
726                 unsigned char *mrdatabegin = mcurrent;
727                 rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
728                 scurrent = sstart;
729                 for (count = 0; count < scount; count++) {
730                         dns_rdata_reset(&srdata);
731                         rdata_from_slab(&scurrent, rdclass, type, &srdata);
732                         if (dns_rdata_compare(&mrdata, &srdata) == 0)
733                                 break;
734                 }
735                 if (count == scount) {
736                         /*
737                          * This rdata isn't in the sslab, and thus isn't
738                          * being subtracted.
739                          */
740                         tlength += mcurrent - mrdatabegin;
741                         tcount++;
742                 } else
743                         rcount++;
744                 dns_rdata_reset(&mrdata);
745         }
746
747         tlength += (4 * tcount);
748
749         /*
750          * Check that all the records originally existed.  The numeric
751          * check only works as rdataslabs do not contain duplicates.
752          */
753         if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount))
754                 return (DNS_R_NOTEXACT);
755
756         /*
757          * Don't continue if the new rdataslab would be empty.
758          */
759         if (tcount == 0)
760                 return (DNS_R_NXRRSET);
761
762         /*
763          * If nothing is going to change, we can stop.
764          */
765         if (rcount == 0)
766                 return (DNS_R_UNCHANGED);
767
768         /*
769          * Copy the reserved area from the mslab.
770          */
771         tstart = isc_mem_get(mctx, tlength);
772         if (tstart == NULL)
773                 return (ISC_R_NOMEMORY);
774         memcpy(tstart, mslab, reservelen);
775         tcurrent = tstart + reservelen;
776         offsetbase = tcurrent;
777
778         offsettable = isc_mem_get(mctx, mcount * sizeof(unsigned int));
779         if (offsettable == NULL) {
780                 isc_mem_put(mctx, tstart, tlength);
781                 return (ISC_R_NOMEMORY);
782         }
783         memset(offsettable, 0, mcount * sizeof(unsigned int));
784
785         /*
786          * Write the new count.
787          */
788         *tcurrent++ = (tcount & 0xff00) >> 8;
789         *tcurrent++ = (tcount & 0x00ff);
790
791         tcurrent += (4 * tcount);
792
793         /*
794          * Copy the parts of mslab not in sslab.
795          */
796         mcurrent = mslab + reservelen;
797         mcount = *mcurrent++ * 256;
798         mcount += *mcurrent++;
799         mcurrent += (4 * mcount);
800         for (i = 0; i < mcount; i++) {
801                 unsigned char *mrdatabegin = mcurrent;
802                 order = mcurrent[2] * 256 + mcurrent[3];
803                 INSIST(order < mcount);
804                 rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
805                 scurrent = sstart;
806                 for (count = 0; count < scount; count++) {
807                         dns_rdata_reset(&srdata);
808                         rdata_from_slab(&scurrent, rdclass, type, &srdata);
809                         if (dns_rdata_compare(&mrdata, &srdata) == 0)
810                                 break;
811                 }
812                 if (count == scount) {
813                         /*
814                          * This rdata isn't in the sslab, and thus should be
815                          * copied to the tslab.
816                          */
817                         unsigned int length = mcurrent - mrdatabegin;
818                         offsettable[order] = tcurrent - offsetbase;
819                         memcpy(tcurrent, mrdatabegin, length);
820                         tcurrent += length;
821                 }
822                 dns_rdata_reset(&mrdata);
823         }
824
825         fillin_offsets(offsetbase, offsettable, mcount);
826
827         isc_mem_put(mctx, offsettable, mcount * sizeof(unsigned int));
828
829         INSIST(tcurrent == tstart + tlength);
830
831         *tslabp = tstart;
832
833         return (ISC_R_SUCCESS);
834 }
835
836 isc_boolean_t
837 dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
838                     unsigned int reservelen)
839 {
840         unsigned char *current1, *current2;
841         unsigned int count1, count2;
842         unsigned int length1, length2;
843
844         current1 = slab1 + reservelen;
845         count1 = *current1++ * 256;
846         count1 += *current1++;
847
848         current2 = slab2 + reservelen;
849         count2 = *current2++ * 256;
850         count2 += *current2++;
851
852         if (count1 != count2)
853                 return (ISC_FALSE);
854
855         current1 += (4 * count1);
856         current2 += (4 * count2);
857
858         while (count1 > 0) {
859                 length1 = *current1++ * 256;
860                 length1 += *current1++;
861
862                 length2 = *current2++ * 256;
863                 length2 += *current2++;
864
865                 current1 += 2;
866                 current2 += 2;
867
868                 if (length1 != length2 ||
869                     memcmp(current1, current2, length1) != 0)
870                         return (ISC_FALSE);
871
872                 current1 += length1;
873                 current2 += length1;
874
875                 count1--;
876         }
877         return (ISC_TRUE);
878 }
879
880 isc_boolean_t
881 dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
882                      unsigned int reservelen, dns_rdataclass_t rdclass,
883                      dns_rdatatype_t type)
884 {
885         unsigned char *current1, *current2;
886         unsigned int count1, count2;
887         dns_rdata_t rdata1 = DNS_RDATA_INIT;
888         dns_rdata_t rdata2 = DNS_RDATA_INIT;
889
890         current1 = slab1 + reservelen;
891         count1 = *current1++ * 256;
892         count1 += *current1++;
893
894         current2 = slab2 + reservelen;
895         count2 = *current2++ * 256;
896         count2 += *current2++;
897
898         if (count1 != count2)
899                 return (ISC_FALSE);
900
901         current1 += (4 * count1);
902         current2 += (4 * count2);
903
904         while (count1-- > 0) {
905                 rdata_from_slab(&current1, rdclass, type, &rdata1);
906                 rdata_from_slab(&current2, rdclass, type, &rdata2);
907                 if (dns_rdata_compare(&rdata1, &rdata2) != 0)
908                         return (ISC_FALSE);
909                 dns_rdata_reset(&rdata1);
910                 dns_rdata_reset(&rdata2);
911         }
912         return (ISC_TRUE);
913 }