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