1 /* $NetBSD: rdataslab.c,v 1.11 2015/07/08 17:28:59 christos Exp $ */
4 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
29 #include <isc/region.h>
30 #include <isc/string.h> /* Required for HP/UX (and others?) */
33 #include <dns/result.h>
34 #include <dns/rdata.h>
35 #include <dns/rdataset.h>
36 #include <dns/rdataslab.h>
39 * The rdataslab structure allows iteration to occur in both load order
40 * and DNSSEC order. The structure is as follows:
42 * header (reservelen bytes)
43 * record count (2 bytes)
44 * offset table (4 x record count bytes in load order)
46 * data length (2 bytes)
48 * meta data (1 byte for RRSIG's)
49 * data (data length bytes)
51 * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
52 * rdataslab is as follows:
54 * header (reservelen bytes)
55 * record count (2 bytes)
57 * data length (2 bytes)
58 * meta data (1 byte for RRSIG's)
59 * data (data length bytes)
61 * Offsets are from the end of the header.
63 * Load order traversal is performed by walking the offset table to find
64 * the start of the record (DNS_RDATASET_FIXED = 1).
66 * DNSSEC order traversal is performed by walking the data records.
68 * The order is stored with record to allow for efficient reconstruction
69 * of the offset table following a merge or subtraction.
71 * The iterator methods here currently only support DNSSEC order iteration.
73 * The iterator methods in rbtdb support both load order and DNSSEC order
77 * rbtdb.c directly interacts with the slab's raw structures. If the
78 * structure changes then rbtdb.c also needs to be updated to reflect
79 * the changes. See the areas tagged with "RDATASLAB".
87 /*% Note: the "const void *" are just to make qsort happy. */
89 compare_rdata(const void *p1
, const void *p2
) {
90 const struct xrdata
*x1
= p1
;
91 const struct xrdata
*x2
= p2
;
92 return (dns_rdata_compare(&x1
->rdata
, &x2
->rdata
));
95 #if DNS_RDATASET_FIXED
97 fillin_offsets(unsigned char *offsetbase
, unsigned int *offsettable
,
103 for (i
= 0, j
= 0; i
< length
; i
++) {
105 if (offsettable
[i
] == 0)
109 * Fill in offset table.
111 raw
= &offsetbase
[j
*4 + 2];
112 *raw
++ = (offsettable
[i
] & 0xff000000) >> 24;
113 *raw
++ = (offsettable
[i
] & 0xff0000) >> 16;
114 *raw
++ = (offsettable
[i
] & 0xff00) >> 8;
115 *raw
= offsettable
[i
] & 0xff;
118 * Fill in table index.
120 raw
= offsetbase
+ offsettable
[i
] + 2;
121 *raw
++ = (j
& 0xff00) >> 8;
128 dns_rdataslab_fromrdataset(dns_rdataset_t
*rdataset
, isc_mem_t
*mctx
,
129 isc_region_t
*region
, unsigned int reservelen
)
132 * Use &removed as a sentinal pointer for duplicate
133 * rdata as rdata.data == NULL is valid.
135 static unsigned char removed
;
137 unsigned char *rawbuf
;
138 #if DNS_RDATASET_FIXED
139 unsigned char *offsetbase
;
146 #if DNS_RDATASET_FIXED
147 unsigned int *offsettable
;
151 buflen
= reservelen
+ 2;
153 nitems
= dns_rdataset_count(rdataset
);
156 * If there are no rdata then we can just need to allocate a header
157 * with zero a record count.
160 if (rdataset
->type
!= 0)
161 return (ISC_R_FAILURE
);
162 rawbuf
= isc_mem_get(mctx
, buflen
);
164 return (ISC_R_NOMEMORY
);
165 region
->base
= rawbuf
;
166 region
->length
= buflen
;
167 rawbuf
+= reservelen
;
170 return (ISC_R_SUCCESS
);
174 return (ISC_R_NOSPACE
);
177 * Remember the original number of items.
180 x
= isc_mem_get(mctx
, nalloc
* sizeof(struct xrdata
));
182 return (ISC_R_NOMEMORY
);
185 * Save all of the rdata members into an array.
187 result
= dns_rdataset_first(rdataset
);
188 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_NOMORE
)
190 for (i
= 0; i
< nalloc
&& result
== ISC_R_SUCCESS
; i
++) {
191 INSIST(result
== ISC_R_SUCCESS
);
192 dns_rdata_init(&x
[i
].rdata
);
193 dns_rdataset_current(rdataset
, &x
[i
].rdata
);
194 INSIST(x
[i
].rdata
.data
!= &removed
);
195 #if DNS_RDATASET_FIXED
198 result
= dns_rdataset_next(rdataset
);
200 if (i
!= nalloc
|| result
!= ISC_R_NOMORE
) {
202 * Somehow we iterated over fewer rdatas than
203 * dns_rdataset_count() said there were or there
204 * were more items than dns_rdataset_count said
207 result
= ISC_R_FAILURE
;
212 * Put into DNSSEC order.
215 qsort(x
, nalloc
, sizeof(struct xrdata
), compare_rdata
);
218 * Remove duplicates and compute the total storage required.
220 * If an rdata is not a duplicate, accumulate the storage size
221 * required for the rdata. We do not store the class, type, etc,
222 * just the rdata, so our overhead is 2 bytes for the number of
223 * records, and 8 for each rdata, (length(2), offset(4) and order(2))
224 * and then the rdata itself.
226 for (i
= 1; i
< nalloc
; i
++) {
227 if (compare_rdata(&x
[i
-1].rdata
, &x
[i
].rdata
) == 0) {
228 x
[i
-1].rdata
.data
= &removed
;
229 #if DNS_RDATASET_FIXED
231 * Preserve the least order so A, B, A -> A, B
232 * after duplicate removal.
234 if (x
[i
-1].order
< x
[i
].order
)
235 x
[i
].order
= x
[i
-1].order
;
239 #if DNS_RDATASET_FIXED
240 buflen
+= (8 + x
[i
-1].rdata
.length
);
242 buflen
+= (2 + x
[i
-1].rdata
.length
);
245 * Provide space to store the per RR meta data.
247 if (rdataset
->type
== dns_rdatatype_rrsig
)
253 * Don't forget the last item!
255 #if DNS_RDATASET_FIXED
256 buflen
+= (8 + x
[i
-1].rdata
.length
);
258 buflen
+= (2 + x
[i
-1].rdata
.length
);
261 * Provide space to store the per RR meta data.
263 if (rdataset
->type
== dns_rdatatype_rrsig
)
267 * Ensure that singleton types are actually singletons.
269 if (nitems
> 1 && dns_rdatatype_issingleton(rdataset
->type
)) {
271 * We have a singleton type, but there's more than one
272 * RR in the rdataset.
274 result
= DNS_R_SINGLETON
;
279 * Allocate the memory, set up a buffer, start copying in
282 rawbuf
= isc_mem_get(mctx
, buflen
);
283 if (rawbuf
== NULL
) {
284 result
= ISC_R_NOMEMORY
;
288 #if DNS_RDATASET_FIXED
289 /* Allocate temporary offset table. */
290 offsettable
= isc_mem_get(mctx
, nalloc
* sizeof(unsigned int));
291 if (offsettable
== NULL
) {
292 isc_mem_put(mctx
, rawbuf
, buflen
);
293 result
= ISC_R_NOMEMORY
;
296 memset(offsettable
, 0, nalloc
* sizeof(unsigned int));
299 region
->base
= rawbuf
;
300 region
->length
= buflen
;
302 rawbuf
+= reservelen
;
303 #if DNS_RDATASET_FIXED
307 *rawbuf
++ = (nitems
& 0xff00) >> 8;
308 *rawbuf
++ = (nitems
& 0x00ff);
310 #if DNS_RDATASET_FIXED
311 /* Skip load order table. Filled in later. */
312 rawbuf
+= nitems
* 4;
315 for (i
= 0; i
< nalloc
; i
++) {
316 if (x
[i
].rdata
.data
== &removed
)
318 #if DNS_RDATASET_FIXED
319 offsettable
[x
[i
].order
] = rawbuf
- offsetbase
;
321 length
= x
[i
].rdata
.length
;
322 if (rdataset
->type
== dns_rdatatype_rrsig
)
324 INSIST(length
<= 0xffff);
325 *rawbuf
++ = (length
& 0xff00) >> 8;
326 *rawbuf
++ = (length
& 0x00ff);
327 #if DNS_RDATASET_FIXED
328 rawbuf
+= 2; /* filled in later */
331 * Store the per RR meta data.
333 if (rdataset
->type
== dns_rdatatype_rrsig
) {
334 *rawbuf
++ |= (x
[i
].rdata
.flags
& DNS_RDATA_OFFLINE
) ?
335 DNS_RDATASLAB_OFFLINE
: 0;
337 memmove(rawbuf
, x
[i
].rdata
.data
, x
[i
].rdata
.length
);
338 rawbuf
+= x
[i
].rdata
.length
;
341 #if DNS_RDATASET_FIXED
342 fillin_offsets(offsetbase
, offsettable
, nalloc
);
343 isc_mem_put(mctx
, offsettable
, nalloc
* sizeof(unsigned int));
346 result
= ISC_R_SUCCESS
;
349 isc_mem_put(mctx
, x
, nalloc
* sizeof(struct xrdata
));
354 rdataset_disassociate(dns_rdataset_t
*rdataset
) {
359 rdataset_first(dns_rdataset_t
*rdataset
) {
360 unsigned char *raw
= rdataset
->private3
;
363 count
= raw
[0] * 256 + raw
[1];
365 rdataset
->private5
= NULL
;
366 return (ISC_R_NOMORE
);
368 #if DNS_RDATASET_FIXED
369 raw
+= 2 + (4 * count
);
374 * The privateuint4 field is the number of rdata beyond the cursor
375 * position, so we decrement the total count by one before storing
379 rdataset
->privateuint4
= count
;
380 rdataset
->private5
= raw
;
382 return (ISC_R_SUCCESS
);
386 rdataset_next(dns_rdataset_t
*rdataset
) {
391 count
= rdataset
->privateuint4
;
393 return (ISC_R_NOMORE
);
395 rdataset
->privateuint4
= count
;
396 raw
= rdataset
->private5
;
397 length
= raw
[0] * 256 + raw
[1];
398 #if DNS_RDATASET_FIXED
403 rdataset
->private5
= raw
;
405 return (ISC_R_SUCCESS
);
409 rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
410 unsigned char *raw
= rdataset
->private5
;
413 unsigned int flags
= 0;
415 REQUIRE(raw
!= NULL
);
417 length
= raw
[0] * 256 + raw
[1];
418 #if DNS_RDATASET_FIXED
423 if (rdataset
->type
== dns_rdatatype_rrsig
) {
424 if (*raw
& DNS_RDATASLAB_OFFLINE
)
425 flags
|= DNS_RDATA_OFFLINE
;
431 dns_rdata_fromregion(rdata
, rdataset
->rdclass
, rdataset
->type
, &r
);
432 rdata
->flags
|= flags
;
436 rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
440 * Reset iterator state.
442 target
->privateuint4
= 0;
443 target
->private5
= NULL
;
447 rdataset_count(dns_rdataset_t
*rdataset
) {
448 unsigned char *raw
= rdataset
->private3
;
451 count
= raw
[0] * 256 + raw
[1];
456 static dns_rdatasetmethods_t rdataset_methods
= {
457 rdataset_disassociate
,
476 dns_rdataslab_tordataset(unsigned char *slab
, unsigned int reservelen
,
477 dns_rdataclass_t rdclass
, dns_rdatatype_t rdtype
,
478 dns_rdatatype_t covers
, dns_ttl_t ttl
,
479 dns_rdataset_t
*rdataset
)
481 REQUIRE(slab
!= NULL
);
482 REQUIRE(!dns_rdataset_isassociated(rdataset
));
484 rdataset
->methods
= &rdataset_methods
;
485 rdataset
->rdclass
= rdclass
;
486 rdataset
->type
= rdtype
;
487 rdataset
->covers
= covers
;
490 rdataset
->private1
= NULL
;
491 rdataset
->private2
= NULL
;
492 rdataset
->private3
= slab
+ reservelen
;
495 * Reset iterator state.
497 rdataset
->privateuint4
= 0;
498 rdataset
->private5
= NULL
;
502 dns_rdataslab_size(unsigned char *slab
, unsigned int reservelen
) {
503 unsigned int count
, length
;
504 unsigned char *current
;
506 REQUIRE(slab
!= NULL
);
508 current
= slab
+ reservelen
;
509 count
= *current
++ * 256;
511 #if DNS_RDATASET_FIXED
512 current
+= (4 * count
);
516 length
= *current
++ * 256;
517 length
+= *current
++;
518 #if DNS_RDATASET_FIXED
519 current
+= length
+ 2;
525 return ((unsigned int)(current
- slab
));
529 * Make the dns_rdata_t 'rdata' refer to the slab item
530 * beginning at '*current', which is part of a slab of type
531 * 'type' and class 'rdclass', and advance '*current' to
532 * point to the next item in the slab.
535 rdata_from_slab(unsigned char **current
,
536 dns_rdataclass_t rdclass
, dns_rdatatype_t type
,
539 unsigned char *tcurrent
= *current
;
542 isc_boolean_t offline
= ISC_FALSE
;
544 length
= *tcurrent
++ * 256;
545 length
+= *tcurrent
++;
547 if (type
== dns_rdatatype_rrsig
) {
548 if ((*tcurrent
& DNS_RDATASLAB_OFFLINE
) != 0)
553 region
.length
= length
;
554 #if DNS_RDATASET_FIXED
557 region
.base
= tcurrent
;
558 tcurrent
+= region
.length
;
559 dns_rdata_fromregion(rdata
, rdclass
, type
, ®ion
);
561 rdata
->flags
|= DNS_RDATA_OFFLINE
;
566 * Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
567 * contains an rdata identical to 'rdata'. This does case insensitive
568 * comparisons per DNSSEC.
570 static inline isc_boolean_t
571 rdata_in_slab(unsigned char *slab
, unsigned int reservelen
,
572 dns_rdataclass_t rdclass
, dns_rdatatype_t type
,
575 unsigned int count
, i
;
576 unsigned char *current
;
577 dns_rdata_t trdata
= DNS_RDATA_INIT
;
580 current
= slab
+ reservelen
;
581 count
= *current
++ * 256;
584 #if DNS_RDATASET_FIXED
585 current
+= (4 * count
);
588 for (i
= 0; i
< count
; i
++) {
589 rdata_from_slab(¤t
, rdclass
, type
, &trdata
);
591 n
= dns_rdata_compare(&trdata
, rdata
);
594 if (n
> 0) /* In DNSSEC order. */
596 dns_rdata_reset(&trdata
);
602 dns_rdataslab_merge(unsigned char *oslab
, unsigned char *nslab
,
603 unsigned int reservelen
, isc_mem_t
*mctx
,
604 dns_rdataclass_t rdclass
, dns_rdatatype_t type
,
605 unsigned int flags
, unsigned char **tslabp
)
607 unsigned char *ocurrent
, *ostart
, *ncurrent
, *tstart
, *tcurrent
, *data
;
608 unsigned int ocount
, ncount
, count
, olength
, tlength
, tcount
, length
;
609 dns_rdata_t ordata
= DNS_RDATA_INIT
;
610 dns_rdata_t nrdata
= DNS_RDATA_INIT
;
611 isc_boolean_t added_something
= ISC_FALSE
;
612 unsigned int oadded
= 0;
613 unsigned int nadded
= 0;
614 unsigned int nncount
= 0;
615 #if DNS_RDATASET_FIXED
616 unsigned int oncount
;
617 unsigned int norder
= 0;
618 unsigned int oorder
= 0;
619 unsigned char *offsetbase
;
620 unsigned int *offsettable
;
624 * XXX Need parameter to allow "delete rdatasets in nslab" merge,
625 * or perhaps another merge routine for this purpose.
628 REQUIRE(tslabp
!= NULL
&& *tslabp
== NULL
);
629 REQUIRE(oslab
!= NULL
&& nslab
!= NULL
);
631 ocurrent
= oslab
+ reservelen
;
632 ocount
= *ocurrent
++ * 256;
633 ocount
+= *ocurrent
++;
634 #if DNS_RDATASET_FIXED
635 ocurrent
+= (4 * ocount
);
638 ncurrent
= nslab
+ reservelen
;
639 ncount
= *ncurrent
++ * 256;
640 ncount
+= *ncurrent
++;
641 #if DNS_RDATASET_FIXED
642 ncurrent
+= (4 * ncount
);
644 INSIST(ocount
> 0 && ncount
> 0);
646 #if DNS_RDATASET_FIXED
651 * Yes, this is inefficient!
655 * Figure out the length of the old slab's data.
658 for (count
= 0; count
< ocount
; count
++) {
659 length
= *ocurrent
++ * 256;
660 length
+= *ocurrent
++;
661 #if DNS_RDATASET_FIXED
662 olength
+= length
+ 8;
663 ocurrent
+= length
+ 2;
665 olength
+= length
+ 2;
671 * Start figuring out the target length and count.
673 tlength
= reservelen
+ 2 + olength
;
677 * Add in the length of rdata in the new slab that aren't in
681 dns_rdata_init(&nrdata
);
682 rdata_from_slab(&ncurrent
, rdclass
, type
, &nrdata
);
683 if (!rdata_in_slab(oslab
, reservelen
, rdclass
, type
, &nrdata
))
686 * This rdata isn't in the old slab.
688 #if DNS_RDATASET_FIXED
689 tlength
+= nrdata
.length
+ 8;
691 tlength
+= nrdata
.length
+ 2;
693 if (type
== dns_rdatatype_rrsig
)
697 added_something
= ISC_TRUE
;
700 } while (ncount
> 0);
703 if (((flags
& DNS_RDATASLAB_EXACT
) != 0) &&
704 (tcount
!= ncount
+ ocount
))
705 return (DNS_R_NOTEXACT
);
707 if (!added_something
&& (flags
& DNS_RDATASLAB_FORCE
) == 0)
708 return (DNS_R_UNCHANGED
);
711 * Ensure that singleton types are actually singletons.
713 if (tcount
> 1 && dns_rdatatype_issingleton(type
)) {
715 * We have a singleton type, but there's more than one
716 * RR in the rdataset.
718 return (DNS_R_SINGLETON
);
722 return (ISC_R_NOSPACE
);
725 * Copy the reserved area from the new slab.
727 tstart
= isc_mem_get(mctx
, tlength
);
729 return (ISC_R_NOMEMORY
);
730 memmove(tstart
, nslab
, reservelen
);
731 tcurrent
= tstart
+ reservelen
;
732 #if DNS_RDATASET_FIXED
733 offsetbase
= tcurrent
;
737 * Write the new count.
739 *tcurrent
++ = (tcount
& 0xff00) >> 8;
740 *tcurrent
++ = (tcount
& 0x00ff);
742 #if DNS_RDATASET_FIXED
746 tcurrent
+= (tcount
* 4);
748 offsettable
= isc_mem_get(mctx
,
749 (ocount
+ oncount
) * sizeof(unsigned int));
750 if (offsettable
== NULL
) {
751 isc_mem_put(mctx
, tstart
, tlength
);
752 return (ISC_R_NOMEMORY
);
754 memset(offsettable
, 0, (ocount
+ oncount
) * sizeof(unsigned int));
758 * Merge the two slabs.
762 #if DNS_RDATASET_FIXED
763 oorder
= ocurrent
[2] * 256 + ocurrent
[3];
764 INSIST(oorder
< ocount
);
766 rdata_from_slab(&ocurrent
, rdclass
, type
, &ordata
);
768 ncurrent
= nslab
+ reservelen
+ 2;
769 #if DNS_RDATASET_FIXED
770 ncurrent
+= (4 * oncount
);
775 dns_rdata_reset(&nrdata
);
776 #if DNS_RDATASET_FIXED
777 norder
= ncurrent
[2] * 256 + ncurrent
[3];
779 INSIST(norder
< oncount
);
781 rdata_from_slab(&ncurrent
, rdclass
, type
, &nrdata
);
782 } while (rdata_in_slab(oslab
, reservelen
, rdclass
,
786 while (oadded
< ocount
|| nadded
< ncount
) {
787 isc_boolean_t fromold
;
788 if (oadded
== ocount
)
790 else if (nadded
== ncount
)
793 fromold
= ISC_TF(compare_rdata(&ordata
, &nrdata
) < 0);
795 #if DNS_RDATASET_FIXED
796 offsettable
[oorder
] = tcurrent
- offsetbase
;
798 length
= ordata
.length
;
800 if (type
== dns_rdatatype_rrsig
) {
804 *tcurrent
++ = (length
& 0xff00) >> 8;
805 *tcurrent
++ = (length
& 0x00ff);
806 #if DNS_RDATASET_FIXED
807 tcurrent
+= 2; /* fill in later */
809 memmove(tcurrent
, data
, length
);
812 if (oadded
< ocount
) {
813 dns_rdata_reset(&ordata
);
814 #if DNS_RDATASET_FIXED
815 oorder
= ocurrent
[2] * 256 + ocurrent
[3];
816 INSIST(oorder
< ocount
);
818 rdata_from_slab(&ocurrent
, rdclass
, type
,
822 #if DNS_RDATASET_FIXED
823 offsettable
[ocount
+ norder
] = tcurrent
- offsetbase
;
825 length
= nrdata
.length
;
827 if (type
== dns_rdatatype_rrsig
) {
831 *tcurrent
++ = (length
& 0xff00) >> 8;
832 *tcurrent
++ = (length
& 0x00ff);
833 #if DNS_RDATASET_FIXED
834 tcurrent
+= 2; /* fill in later */
836 memmove(tcurrent
, data
, length
);
839 if (nadded
< ncount
) {
841 dns_rdata_reset(&nrdata
);
842 #if DNS_RDATASET_FIXED
843 norder
= ncurrent
[2] * 256 + ncurrent
[3];
844 INSIST(norder
< oncount
);
846 rdata_from_slab(&ncurrent
, rdclass
,
848 } while (rdata_in_slab(oslab
, reservelen
,
855 #if DNS_RDATASET_FIXED
856 fillin_offsets(offsetbase
, offsettable
, ocount
+ oncount
);
858 isc_mem_put(mctx
, offsettable
,
859 (ocount
+ oncount
) * sizeof(unsigned int));
862 INSIST(tcurrent
== tstart
+ tlength
);
866 return (ISC_R_SUCCESS
);
870 dns_rdataslab_subtract(unsigned char *mslab
, unsigned char *sslab
,
871 unsigned int reservelen
, isc_mem_t
*mctx
,
872 dns_rdataclass_t rdclass
, dns_rdatatype_t type
,
873 unsigned int flags
, unsigned char **tslabp
)
875 unsigned char *mcurrent
, *sstart
, *scurrent
, *tstart
, *tcurrent
;
876 unsigned int mcount
, scount
, rcount
,count
, tlength
, tcount
, i
;
877 dns_rdata_t srdata
= DNS_RDATA_INIT
;
878 dns_rdata_t mrdata
= DNS_RDATA_INIT
;
879 #if DNS_RDATASET_FIXED
880 unsigned char *offsetbase
;
881 unsigned int *offsettable
;
885 REQUIRE(tslabp
!= NULL
&& *tslabp
== NULL
);
886 REQUIRE(mslab
!= NULL
&& sslab
!= NULL
);
888 mcurrent
= mslab
+ reservelen
;
889 mcount
= *mcurrent
++ * 256;
890 mcount
+= *mcurrent
++;
891 scurrent
= sslab
+ reservelen
;
892 scount
= *scurrent
++ * 256;
893 scount
+= *scurrent
++;
894 INSIST(mcount
> 0 && scount
> 0);
897 * Yes, this is inefficient!
901 * Start figuring out the target length and count.
903 tlength
= reservelen
+ 2;
907 #if DNS_RDATASET_FIXED
908 mcurrent
+= 4 * mcount
;
909 scurrent
+= 4 * scount
;
914 * Add in the length of rdata in the mslab that aren't in
917 for (i
= 0; i
< mcount
; i
++) {
918 unsigned char *mrdatabegin
= mcurrent
;
919 rdata_from_slab(&mcurrent
, rdclass
, type
, &mrdata
);
921 for (count
= 0; count
< scount
; count
++) {
922 dns_rdata_reset(&srdata
);
923 rdata_from_slab(&scurrent
, rdclass
, type
, &srdata
);
924 if (dns_rdata_compare(&mrdata
, &srdata
) == 0)
927 if (count
== scount
) {
929 * This rdata isn't in the sslab, and thus isn't
932 tlength
+= (unsigned int)(mcurrent
- mrdatabegin
);
936 dns_rdata_reset(&mrdata
);
939 #if DNS_RDATASET_FIXED
940 tlength
+= (4 * tcount
);
944 * Check that all the records originally existed. The numeric
945 * check only works as rdataslabs do not contain duplicates.
947 if (((flags
& DNS_RDATASLAB_EXACT
) != 0) && (rcount
!= scount
))
948 return (DNS_R_NOTEXACT
);
951 * Don't continue if the new rdataslab would be empty.
954 return (DNS_R_NXRRSET
);
957 * If nothing is going to change, we can stop.
960 return (DNS_R_UNCHANGED
);
963 * Copy the reserved area from the mslab.
965 tstart
= isc_mem_get(mctx
, tlength
);
967 return (ISC_R_NOMEMORY
);
968 memmove(tstart
, mslab
, reservelen
);
969 tcurrent
= tstart
+ reservelen
;
970 #if DNS_RDATASET_FIXED
971 offsetbase
= tcurrent
;
973 offsettable
= isc_mem_get(mctx
, mcount
* sizeof(unsigned int));
974 if (offsettable
== NULL
) {
975 isc_mem_put(mctx
, tstart
, tlength
);
976 return (ISC_R_NOMEMORY
);
978 memset(offsettable
, 0, mcount
* sizeof(unsigned int));
982 * Write the new count.
984 *tcurrent
++ = (tcount
& 0xff00) >> 8;
985 *tcurrent
++ = (tcount
& 0x00ff);
987 #if DNS_RDATASET_FIXED
988 tcurrent
+= (4 * tcount
);
992 * Copy the parts of mslab not in sslab.
994 mcurrent
= mslab
+ reservelen
;
995 mcount
= *mcurrent
++ * 256;
996 mcount
+= *mcurrent
++;
997 #if DNS_RDATASET_FIXED
998 mcurrent
+= (4 * mcount
);
1000 for (i
= 0; i
< mcount
; i
++) {
1001 unsigned char *mrdatabegin
= mcurrent
;
1002 #if DNS_RDATASET_FIXED
1003 order
= mcurrent
[2] * 256 + mcurrent
[3];
1004 INSIST(order
< mcount
);
1006 rdata_from_slab(&mcurrent
, rdclass
, type
, &mrdata
);
1008 for (count
= 0; count
< scount
; count
++) {
1009 dns_rdata_reset(&srdata
);
1010 rdata_from_slab(&scurrent
, rdclass
, type
, &srdata
);
1011 if (dns_rdata_compare(&mrdata
, &srdata
) == 0)
1014 if (count
== scount
) {
1016 * This rdata isn't in the sslab, and thus should be
1017 * copied to the tslab.
1019 unsigned int length
;
1020 length
= (unsigned int)(mcurrent
- mrdatabegin
);
1021 #if DNS_RDATASET_FIXED
1022 offsettable
[order
] = tcurrent
- offsetbase
;
1024 memmove(tcurrent
, mrdatabegin
, length
);
1027 dns_rdata_reset(&mrdata
);
1030 #if DNS_RDATASET_FIXED
1031 fillin_offsets(offsetbase
, offsettable
, mcount
);
1033 isc_mem_put(mctx
, offsettable
, mcount
* sizeof(unsigned int));
1036 INSIST(tcurrent
== tstart
+ tlength
);
1040 return (ISC_R_SUCCESS
);
1044 dns_rdataslab_equal(unsigned char *slab1
, unsigned char *slab2
,
1045 unsigned int reservelen
)
1047 unsigned char *current1
, *current2
;
1048 unsigned int count1
, count2
;
1049 unsigned int length1
, length2
;
1051 current1
= slab1
+ reservelen
;
1052 count1
= *current1
++ * 256;
1053 count1
+= *current1
++;
1055 current2
= slab2
+ reservelen
;
1056 count2
= *current2
++ * 256;
1057 count2
+= *current2
++;
1059 if (count1
!= count2
)
1062 #if DNS_RDATASET_FIXED
1063 current1
+= (4 * count1
);
1064 current2
+= (4 * count2
);
1067 while (count1
> 0) {
1068 length1
= *current1
++ * 256;
1069 length1
+= *current1
++;
1071 length2
= *current2
++ * 256;
1072 length2
+= *current2
++;
1074 #if DNS_RDATASET_FIXED
1079 if (length1
!= length2
||
1080 memcmp(current1
, current2
, length1
) != 0)
1083 current1
+= length1
;
1084 current2
+= length1
;
1092 dns_rdataslab_equalx(unsigned char *slab1
, unsigned char *slab2
,
1093 unsigned int reservelen
, dns_rdataclass_t rdclass
,
1094 dns_rdatatype_t type
)
1096 unsigned char *current1
, *current2
;
1097 unsigned int count1
, count2
;
1098 dns_rdata_t rdata1
= DNS_RDATA_INIT
;
1099 dns_rdata_t rdata2
= DNS_RDATA_INIT
;
1101 current1
= slab1
+ reservelen
;
1102 count1
= *current1
++ * 256;
1103 count1
+= *current1
++;
1105 current2
= slab2
+ reservelen
;
1106 count2
= *current2
++ * 256;
1107 count2
+= *current2
++;
1109 if (count1
!= count2
)
1112 #if DNS_RDATASET_FIXED
1113 current1
+= (4 * count1
);
1114 current2
+= (4 * count2
);
1117 while (count1
-- > 0) {
1118 rdata_from_slab(¤t1
, rdclass
, type
, &rdata1
);
1119 rdata_from_slab(¤t2
, rdclass
, type
, &rdata2
);
1120 if (dns_rdata_compare(&rdata1
, &rdata2
) != 0)
1122 dns_rdata_reset(&rdata1
);
1123 dns_rdata_reset(&rdata2
);