xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rbt.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
1 /*	$NetBSD: rbt.c,v 1.5 2019/11/27 05:48:41 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <config.h>
17 
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <sys/stat.h>
21 
22 #include <isc/crc64.h>
23 #include <isc/file.h>
24 #include <isc/hex.h>
25 #include <isc/mem.h>
26 #include <isc/once.h>
27 #include <isc/platform.h>
28 #include <isc/print.h>
29 #include <isc/refcount.h>
30 #include <isc/socket.h>
31 #include <isc/stdio.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34 
35 /*%
36  * This define is so dns/name.h (included by dns/fixedname.h) uses more
37  * efficient macro calls instead of functions for a few operations.
38  */
39 #define DNS_NAME_USEINLINE 1
40 
41 #include <dns/fixedname.h>
42 #include <dns/log.h>
43 #include <dns/rbt.h>
44 #include <dns/result.h>
45 #include <dns/version.h>
46 
47 #include <unistd.h>
48 
49 #define CHECK(x) \
50 	do { \
51 		result = (x); \
52 		if (result != ISC_R_SUCCESS) \
53 			goto cleanup; \
54 	} while (/*CONSTCOND*/0)
55 
56 #define RBT_MAGIC               ISC_MAGIC('R', 'B', 'T', '+')
57 #define VALID_RBT(rbt)          ISC_MAGIC_VALID(rbt, RBT_MAGIC)
58 
59 /*
60  * XXXDCL Since parent pointers were added in again, I could remove all of the
61  * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
62  * _lastnode.  This would involve pretty major change to the API.
63  */
64 #define CHAIN_MAGIC             ISC_MAGIC('0', '-', '0', '-')
65 #define VALID_CHAIN(chain)      ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
66 
67 #define RBT_HASH_SIZE           64
68 
69 #ifdef RBT_MEM_TEST
70 #undef RBT_HASH_SIZE
71 #define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
72 #endif
73 
74 struct dns_rbt {
75 	unsigned int		magic;
76 	isc_mem_t *		mctx;
77 	dns_rbtnode_t *		root;
78 	void			(*data_deleter)(void *, void *);
79 	void *			deleter_arg;
80 	unsigned int		nodecount;
81 	size_t			hashsize;
82 	dns_rbtnode_t **	hashtable;
83 	void *			mmap_location;
84 };
85 
86 #define RED 0
87 #define BLACK 1
88 
89 /*
90  * This is the header for map-format RBT images.  It is populated,
91  * and then written, as the LAST thing done to the file before returning.
92  * Writing this last (with zeros in the header area initially) will ensure
93  * that the header is only valid when the RBT image is also valid.
94  */
95 typedef struct file_header file_header_t;
96 
97 /* Pad to 32 bytes */
98 static char FILE_VERSION[32] = "\0";
99 
100 /* Header length, always the same size regardless of structure size */
101 #define HEADER_LENGTH		1024
102 
103 struct file_header {
104 	char version1[32];
105 	uint64_t first_node_offset;	/* usually 1024 */
106 	/*
107 	 * information about the system on which the map file was generated
108 	 * will be used to tell if we can load the map file or not
109 	 */
110 	uint32_t ptrsize;
111 	unsigned int bigendian:1;	/* big or little endian system */
112 	unsigned int rdataset_fixed:1;	/* compiled with --enable-rrset-fixed */
113 	unsigned int nodecount;		/* shadow from rbt structure */
114 	uint64_t crc;
115 	char version2[32];  		/* repeated; must match version1 */
116 };
117 
118 /*
119  * The following declarations are for the serialization of an RBT:
120  *
121  * step one: write out a zeroed header of 1024 bytes
122  * step two: walk the tree in a depth-first, left-right-down order, writing
123  * out the nodes, reserving space as we go, correcting addresses to point
124  * at the proper offset in the file, and setting a flag for each pointer to
125  * indicate that it is a reference to a location in the file, rather than in
126  * memory.
127  * step three: write out the header, adding the information that will be
128  * needed to re-create the tree object itself.
129  *
130  * The RBTDB object will do this three times, once for each of the three
131  * RBT objects it contains.
132  *
133  * Note: 'file' must point an actual open file that can be mmapped
134  * and fseeked, not to a pipe or stream
135  */
136 
137 static isc_result_t
138 dns_rbt_zero_header(FILE *file);
139 
140 static isc_result_t
141 write_header(FILE *file, dns_rbt_t *rbt, uint64_t first_node_offset,
142 	     uint64_t crc);
143 
144 static bool
145 match_header_version(file_header_t *header);
146 
147 static isc_result_t
148 serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
149 	       uintptr_t right, uintptr_t down, uintptr_t parent,
150 	       uintptr_t data, uint64_t *crc);
151 
152 static isc_result_t
153 serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
154 		dns_rbtdatawriter_t datawriter, void *writer_arg,
155 		uintptr_t *where, uint64_t *crc);
156 
157 /*
158  * The following functions allow you to get the actual address of a pointer
159  * without having to use an if statement to check to see if that address is
160  * relative or not
161  */
162 static inline dns_rbtnode_t *
163 getparent(dns_rbtnode_t *node, file_header_t *header) {
164 	char *adjusted_address = (char *)(node->parent);
165 	adjusted_address += node->parent_is_relative * (uintptr_t)header;
166 
167 	return ((dns_rbtnode_t *)adjusted_address);
168 }
169 
170 static inline dns_rbtnode_t *
171 getleft(dns_rbtnode_t *node, file_header_t *header) {
172 	char *adjusted_address = (char *)(node->left);
173 	adjusted_address += node->left_is_relative * (uintptr_t)header;
174 
175 	return ((dns_rbtnode_t *)adjusted_address);
176 }
177 
178 static inline dns_rbtnode_t *
179 getright(dns_rbtnode_t *node, file_header_t *header) {
180 	char *adjusted_address = (char *)(node->right);
181 	adjusted_address += node->right_is_relative * (uintptr_t)header;
182 
183 	return ((dns_rbtnode_t *)adjusted_address);
184 }
185 
186 static inline dns_rbtnode_t *
187 getdown(dns_rbtnode_t *node, file_header_t *header) {
188 	char *adjusted_address = (char *)(node->down);
189 	adjusted_address += node->down_is_relative * (uintptr_t)header;
190 
191 	return ((dns_rbtnode_t *)adjusted_address);
192 }
193 
194 static inline dns_rbtnode_t *
195 getdata(dns_rbtnode_t *node, file_header_t *header) {
196 	char *adjusted_address = (char *)(node->data);
197 	adjusted_address += node->data_is_relative * (uintptr_t)header;
198 
199 	return ((dns_rbtnode_t *)adjusted_address);
200 }
201 
202 /*%
203  * Elements of the rbtnode structure.
204  */
205 #define PARENT(node)            ((node)->parent)
206 #define LEFT(node)              ((node)->left)
207 #define RIGHT(node)             ((node)->right)
208 #define DOWN(node)              ((node)->down)
209 #define UPPERNODE(node)         ((node)->uppernode)
210 #define DATA(node)              ((node)->data)
211 #define IS_EMPTY(node)          ((node)->data == NULL)
212 #define HASHNEXT(node)          ((node)->hashnext)
213 #define HASHVAL(node)           ((node)->hashval)
214 #define COLOR(node)             ((node)->color)
215 #define NAMELEN(node)           ((node)->namelen)
216 #define OLDNAMELEN(node)        ((node)->oldnamelen)
217 #define OFFSETLEN(node)         ((node)->offsetlen)
218 #define ATTRS(node)             ((node)->attributes)
219 #define IS_ROOT(node)           ((node)->is_root)
220 #define FINDCALLBACK(node)      ((node)->find_callback)
221 
222 /*%
223  * Structure elements from the rbtdb.c, not
224  * used as part of the rbt.c algorithms.
225  */
226 #define DIRTY(node)     ((node)->dirty)
227 #define WILD(node)      ((node)->wild)
228 #define LOCKNUM(node)   ((node)->locknum)
229 
230 /*%
231  * The variable length stuff stored after the node has the following
232  * structure.
233  *
234  *	&lt;name_data&gt;{1..255}&lt;oldoffsetlen&gt;{1}&lt;offsets&gt;{1..128}
235  *
236  * &lt;name_data&gt; contains the name of the node when it was created.
237  * &lt;oldoffsetlen&gt; contains the length of &lt;offsets&gt; when the node
238  * was created.
239  * &lt;offsets&gt; contains the offets into name for each label when the node
240  * was created.
241  */
242 
243 #define NAME(node)      ((unsigned char *)((node) + 1))
244 #define OFFSETS(node)   (NAME(node) + OLDNAMELEN(node) + 1)
245 #define OLDOFFSETLEN(node) (OFFSETS(node)[-1])
246 
247 #define NODE_SIZE(node) (sizeof(*node) + \
248 			 OLDNAMELEN(node) + OLDOFFSETLEN(node) + 1)
249 
250 /*%
251  * Color management.
252  */
253 #define IS_RED(node)            ((node) != NULL && (node)->color == RED)
254 #define IS_BLACK(node)          ((node) == NULL || (node)->color == BLACK)
255 #define MAKE_RED(node)          ((node)->color = RED)
256 #define MAKE_BLACK(node)        ((node)->color = BLACK)
257 
258 /*%
259  * Chain management.
260  *
261  * The "ancestors" member of chains were removed, with their job now
262  * being wholly handled by parent pointers (which didn't exist, because
263  * of memory concerns, when chains were first implemented).
264  */
265 #define ADD_LEVEL(chain, node) \
266 	do { \
267 		INSIST((chain)->level_count < DNS_RBT_LEVELBLOCK); \
268 		(chain)->levels[(chain)->level_count++] = (node); \
269 	} while (0)
270 
271 /*%
272  * The following macros directly access normally private name variables.
273  * These macros are used to avoid a lot of function calls in the critical
274  * path of the tree traversal code.
275  */
276 
277 static inline void
278 NODENAME(dns_rbtnode_t *node, dns_name_t *name) {
279 	name->length = NAMELEN(node);
280 	name->labels = OFFSETLEN(node);
281 	name->ndata = NAME(node);
282 	name->offsets = OFFSETS(node);
283 	name->attributes = ATTRS(node);
284 	name->attributes |= DNS_NAMEATTR_READONLY;
285 }
286 
287 void
288 dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name) {
289 	name->length = NAMELEN(node);
290 	name->labels = OFFSETLEN(node);
291 	name->ndata = NAME(node);
292 	name->offsets = OFFSETS(node);
293 	name->attributes = ATTRS(node);
294 	name->attributes |= DNS_NAMEATTR_READONLY;
295 }
296 
297 dns_rbtnode_t *
298 dns_rbt_root(dns_rbt_t *rbt) {
299 	return (rbt->root);
300 }
301 
302 #ifdef DEBUG
303 #define inline
304 /*
305  * A little something to help out in GDB.
306  */
307 dns_name_t Name(dns_rbtnode_t *node);
308 dns_name_t
309 Name(dns_rbtnode_t *node) {
310 	dns_name_t name;
311 
312 	dns_name_init(&name, NULL);
313 	if (node != NULL)
314 		NODENAME(node, &name);
315 
316 	return (name);
317 }
318 
319 static void
320 hexdump(const char *desc, void *blob, size_t size) {
321 	char hexdump[BUFSIZ * 2 + 1];
322 	isc_buffer_t b;
323 	isc_region_t r;
324 	isc_result_t result;
325 	size_t bytes;
326 	uint8_t *data = blob;
327 
328 	fprintf(stderr, "%s: ", desc);
329 	do {
330 		isc_buffer_init(&b, hexdump, sizeof(hexdump));
331 		r.base = data;
332 		r.length = bytes = (size > BUFSIZ) ? BUFSIZ : size;
333 		result = isc_hex_totext(&r, 0, "", &b);
334 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
335 		isc_buffer_putuint8(&b, 0);
336 		fprintf(stderr, "%s", hexdump);
337 		data += bytes;
338 		size -= bytes;
339 	} while (size > 0);
340 	fprintf(stderr, "\n");
341 }
342 #endif /* DEBUG */
343 
344 /*
345  * Upper node is the parent of the root of the passed node's
346  * subtree. The passed node must not be NULL.
347  */
348 static inline dns_rbtnode_t *
349 get_upper_node(dns_rbtnode_t *node) {
350 	return (UPPERNODE(node));
351 }
352 
353 static void
354 fixup_uppernodes_helper(dns_rbtnode_t *node, dns_rbtnode_t *uppernode) {
355 	if (node == NULL)
356 		return;
357 
358 	UPPERNODE(node) = uppernode;
359 
360 	fixup_uppernodes_helper(LEFT(node), uppernode);
361 	fixup_uppernodes_helper(RIGHT(node), uppernode);
362 	fixup_uppernodes_helper(DOWN(node), node);
363 }
364 
365 /*
366  * This function is used to fixup uppernode members of all dns_rbtnodes
367  * after deserialization.
368  */
369 static void
370 fixup_uppernodes(dns_rbt_t *rbt) {
371 	fixup_uppernodes_helper(rbt->root, NULL);
372 }
373 
374 size_t
375 dns__rbtnode_getdistance(dns_rbtnode_t *node) {
376 	size_t nodes = 1;
377 
378 	while (node != NULL) {
379 		if (IS_ROOT(node))
380 			break;
381 		nodes++;
382 		node = PARENT(node);
383 	}
384 
385 	return (nodes);
386 }
387 
388 /*
389  * Forward declarations.
390  */
391 static isc_result_t
392 create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep);
393 
394 static isc_result_t
395 inithash(dns_rbt_t *rbt);
396 
397 static inline void
398 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, const dns_name_t *name);
399 
400 static inline void
401 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node);
402 
403 static void
404 rehash(dns_rbt_t *rbt, unsigned int newcount);
405 
406 static inline void
407 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
408 static inline void
409 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
410 
411 static void
412 addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
413 	   dns_rbtnode_t **rootp);
414 
415 static void
416 deletefromlevel(dns_rbtnode_t *item, dns_rbtnode_t **rootp);
417 
418 static isc_result_t
419 treefix(dns_rbt_t *rbt, void *base, size_t size,
420 	dns_rbtnode_t *n, const dns_name_t *name,
421 	dns_rbtdatafixer_t datafixer, void *fixer_arg,
422 	uint64_t *crc);
423 
424 static void
425 deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, bool unhash,
426 	       dns_rbtnode_t **nodep);
427 
428 static void
429 printnodename(dns_rbtnode_t *node, bool quoted, FILE *f);
430 
431 static void
432 freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep);
433 
434 static isc_result_t
435 dns_rbt_zero_header(FILE *file) {
436 	/*
437 	 * Write out a zeroed header as a placeholder.  Doing this ensures
438 	 * that the file will not read while it is partially written, should
439 	 * writing fail or be interrupted.
440 	 */
441 	char buffer[HEADER_LENGTH];
442 	isc_result_t result;
443 
444 	memset(buffer, 0, HEADER_LENGTH);
445 	result = isc_stdio_write(buffer, 1, HEADER_LENGTH, file, NULL);
446 	if (result != ISC_R_SUCCESS)
447 		return (result);
448 
449 	result = fflush(file);
450 	if (result != ISC_R_SUCCESS)
451 		return (result);
452 
453 	return (ISC_R_SUCCESS);
454 }
455 
456 static isc_once_t once = ISC_ONCE_INIT;
457 
458 static void
459 init_file_version(void) {
460 	int n;
461 
462 	memset(FILE_VERSION, 0, sizeof(FILE_VERSION));
463 	n = snprintf(FILE_VERSION, sizeof(FILE_VERSION),
464 		 "RBT Image %s %s", dns_major, dns_mapapi);
465 	INSIST(n > 0 && (unsigned int)n < sizeof(FILE_VERSION));
466 }
467 
468 /*
469  * Write out the real header, including NodeDump version information
470  * and the offset of the first node.
471  *
472  * Any information stored in the rbt object itself should be stored
473  * here.
474  */
475 static isc_result_t
476 write_header(FILE *file, dns_rbt_t *rbt, uint64_t first_node_offset,
477 	     uint64_t crc)
478 {
479 	file_header_t header;
480 	isc_result_t result;
481 	off_t location;
482 
483 	RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS);
484 
485 	memset(&header, 0, sizeof(file_header_t));
486 	memmove(header.version1, FILE_VERSION, sizeof(header.version1));
487 	memmove(header.version2, FILE_VERSION, sizeof(header.version2));
488 	header.first_node_offset = first_node_offset;
489 	header.ptrsize = (uint32_t) sizeof(void *);
490 	header.bigendian = (1 == htonl(1)) ? 1 : 0;
491 
492 #ifdef DNS_RDATASET_FIXED
493 	header.rdataset_fixed = 1;
494 #else
495 	header.rdataset_fixed = 0;
496 #endif
497 
498 	header.nodecount = rbt->nodecount;
499 
500 	header.crc = crc;
501 
502 	CHECK(isc_stdio_tell(file, &location));
503 	location = dns_rbt_serialize_align(location);
504 	CHECK(isc_stdio_seek(file, location, SEEK_SET));
505 	CHECK(isc_stdio_write(&header, 1, sizeof(file_header_t), file, NULL));
506 	CHECK(fflush(file));
507 
508 	/* Ensure we are always at the end of the file. */
509 	CHECK(isc_stdio_seek(file, 0, SEEK_END));
510 
511  cleanup:
512 	return (result);
513 }
514 
515 static bool
516 match_header_version(file_header_t *header) {
517 	RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS);
518 
519 	if (memcmp(header->version1, FILE_VERSION,
520 		   sizeof(header->version1)) != 0 ||
521 	    memcmp(header->version2, FILE_VERSION,
522 		   sizeof(header->version1)) != 0)
523 	{
524 		return (false);
525 	}
526 
527 	return (true);
528 }
529 
530 static isc_result_t
531 serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
532 	       uintptr_t right, uintptr_t down, uintptr_t parent,
533 	       uintptr_t data, uint64_t *crc)
534 {
535 	dns_rbtnode_t temp_node;
536 	off_t file_position;
537 	unsigned char *node_data;
538 	size_t datasize;
539 	isc_result_t result;
540 #ifdef DEBUG
541 	dns_name_t nodename;
542 #endif
543 
544 	INSIST(node != NULL);
545 
546 	CHECK(isc_stdio_tell(file, &file_position));
547 	file_position = dns_rbt_serialize_align(file_position);
548 	CHECK(isc_stdio_seek(file, file_position, SEEK_SET));
549 
550 	temp_node = *node;
551 	temp_node.down_is_relative = 0;
552 	temp_node.left_is_relative = 0;
553 	temp_node.right_is_relative = 0;
554 	temp_node.parent_is_relative = 0;
555 	temp_node.data_is_relative = 0;
556 	temp_node.is_mmapped = 1;
557 
558 	/*
559 	 * If the next node is not NULL, calculate the next node's location
560 	 * in the file.  Note that this will have to change when the data
561 	 * structure changes, and it also assumes that we always write the
562 	 * nodes out in list order (which we currently do.)
563 	*/
564 	if (temp_node.parent != NULL) {
565 		temp_node.parent = (dns_rbtnode_t *)(parent);
566 		temp_node.parent_is_relative = 1;
567 	}
568 	if (temp_node.left != NULL) {
569 		temp_node.left = (dns_rbtnode_t *)(left);
570 		temp_node.left_is_relative = 1;
571 	}
572 	if (temp_node.right != NULL) {
573 		temp_node.right = (dns_rbtnode_t *)(right);
574 		temp_node.right_is_relative = 1;
575 	}
576 	if (temp_node.down != NULL) {
577 		temp_node.down = (dns_rbtnode_t *)(down);
578 		temp_node.down_is_relative = 1;
579 	}
580 	if (temp_node.data != NULL) {
581 		temp_node.data = (dns_rbtnode_t *)(data);
582 		temp_node.data_is_relative = 1;
583 	}
584 
585 	node_data = (unsigned char *) node + sizeof(dns_rbtnode_t);
586 	datasize = NODE_SIZE(node) - sizeof(dns_rbtnode_t);
587 
588 	CHECK(isc_stdio_write(&temp_node, 1, sizeof(dns_rbtnode_t),
589 			      file, NULL));
590 	CHECK(isc_stdio_write(node_data, 1, datasize, file, NULL));
591 
592 #ifdef DEBUG
593 	dns_name_init(&nodename, NULL);
594 	NODENAME(node, &nodename);
595 	fprintf(stderr, "serialize ");
596 	dns_name_print(&nodename, stderr);
597 	fprintf(stderr, "\n");
598 	hexdump("node header", &temp_node,
599 		sizeof(dns_rbtnode_t));
600 	hexdump("node data", node_data, datasize);
601 #endif
602 
603 	isc_crc64_update(crc, (const uint8_t *) &temp_node,
604 			 sizeof(dns_rbtnode_t));
605 	isc_crc64_update(crc, (const uint8_t *) node_data, datasize);
606 
607  cleanup:
608 	return (result);
609 }
610 
611 static isc_result_t
612 serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
613 		dns_rbtdatawriter_t datawriter, void *writer_arg,
614 		uintptr_t *where, uint64_t *crc)
615 {
616 	uintptr_t left = 0, right = 0, down = 0, data = 0;
617 	off_t location = 0, offset_adjust;
618 	isc_result_t result;
619 
620 	if (node == NULL) {
621 		if (where != NULL)
622 			*where = 0;
623 		return (ISC_R_SUCCESS);
624 	}
625 
626 	/* Reserve space for current node. */
627 	CHECK(isc_stdio_tell(file, &location));
628 	location = dns_rbt_serialize_align(location);
629 	CHECK(isc_stdio_seek(file, location, SEEK_SET));
630 
631 	offset_adjust = dns_rbt_serialize_align(location + NODE_SIZE(node));
632 	CHECK(isc_stdio_seek(file, offset_adjust, SEEK_SET));
633 
634 	/*
635 	 * Serialize the rest of the tree.
636 	 *
637 	 * WARNING: A change in the order (from left, right, down)
638 	 * will break the way the crc hash is computed.
639 	 */
640 	CHECK(serialize_nodes(file, getleft(node, NULL), location,
641 			      datawriter, writer_arg, &left, crc));
642 	CHECK(serialize_nodes(file, getright(node, NULL), location,
643 			      datawriter, writer_arg, &right, crc));
644 	CHECK(serialize_nodes(file, getdown(node, NULL), location,
645 			      datawriter, writer_arg, &down, crc));
646 
647 	if (node->data != NULL) {
648 		off_t ret;
649 
650 		CHECK(isc_stdio_tell(file, &ret));
651 		ret = dns_rbt_serialize_align(ret);
652 		CHECK(isc_stdio_seek(file, ret, SEEK_SET));
653 		data = ret;
654 
655 		datawriter(file, node->data, writer_arg, crc);
656 	}
657 
658 	/* Seek back to reserved space. */
659 	CHECK(isc_stdio_seek(file, location, SEEK_SET));
660 
661 	/* Serialize the current node. */
662 	CHECK(serialize_node(file, node, left, right, down, parent, data, crc));
663 
664 	/* Ensure we are always at the end of the file. */
665 	CHECK(isc_stdio_seek(file, 0, SEEK_END));
666 
667 	if (where != NULL)
668 		*where = (uintptr_t) location;
669 
670  cleanup:
671 	return (result);
672 }
673 
674 off_t
675 dns_rbt_serialize_align(off_t target) {
676 	off_t offset = target % 8;
677 
678 	if (offset == 0)
679 		return (target);
680 	else
681 		return (target + 8 - offset);
682 }
683 
684 isc_result_t
685 dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt,
686 		       dns_rbtdatawriter_t datawriter,
687 		       void *writer_arg, off_t *offset)
688 {
689 	isc_result_t result;
690 	off_t header_position, node_position, end_position;
691 	uint64_t crc;
692 
693 	REQUIRE(file != NULL);
694 
695 	CHECK(isc_file_isplainfilefd(fileno(file)));
696 
697 	isc_crc64_init(&crc);
698 
699 	CHECK(isc_stdio_tell(file, &header_position));
700 
701 	/* Write dummy header */
702 	CHECK(dns_rbt_zero_header(file));
703 
704 	/* Serialize nodes */
705 	CHECK(isc_stdio_tell(file, &node_position));
706 	CHECK(serialize_nodes(file, rbt->root, 0, datawriter,
707 			      writer_arg, NULL, &crc));
708 
709 	CHECK(isc_stdio_tell(file, &end_position));
710 	if (node_position == end_position) {
711 		CHECK(isc_stdio_seek(file, header_position, SEEK_SET));
712 		*offset = 0;
713 		return (ISC_R_SUCCESS);
714 	}
715 
716 	isc_crc64_final(&crc);
717 #ifdef DEBUG
718 	hexdump("serializing CRC", &crc, sizeof(crc));
719 #endif
720 
721 	/* Serialize header */
722 	CHECK(isc_stdio_seek(file, header_position, SEEK_SET));
723 	CHECK(write_header(file, rbt, HEADER_LENGTH, crc));
724 
725 	/* Ensure we are always at the end of the file. */
726 	CHECK(isc_stdio_seek(file, 0, SEEK_END));
727 	*offset = dns_rbt_serialize_align(header_position);
728 
729  cleanup:
730 	return (result);
731 }
732 
733 #define CONFIRM(a) do { \
734 	if (! (a)) { \
735 		result = ISC_R_INVALIDFILE; \
736 		goto cleanup; \
737 	} \
738 } while(/*CONSTCOND*/0);
739 
740 static isc_result_t
741 treefix(dns_rbt_t *rbt, void *base, size_t filesize, dns_rbtnode_t *n,
742 	const dns_name_t *name, dns_rbtdatafixer_t datafixer,
743 	void *fixer_arg, uint64_t *crc)
744 {
745 	isc_result_t result = ISC_R_SUCCESS;
746 	dns_fixedname_t fixed;
747 	dns_name_t nodename, *fullname;
748 	unsigned char *node_data;
749 	dns_rbtnode_t header;
750 	size_t datasize, nodemax = filesize - sizeof(dns_rbtnode_t);
751 
752 	if (n == NULL)
753 		return (ISC_R_SUCCESS);
754 
755 	CONFIRM((void *) n >= base);
756 	CONFIRM((char *) n - (char *) base <= (int) nodemax);
757 	CONFIRM(DNS_RBTNODE_VALID(n));
758 
759 	dns_name_init(&nodename, NULL);
760 	NODENAME(n, &nodename);
761 
762 	fullname = &nodename;
763 	CONFIRM(dns_name_isvalid(fullname));
764 
765 	if (!dns_name_isabsolute(&nodename)) {
766 		fullname = dns_fixedname_initname(&fixed);
767 		CHECK(dns_name_concatenate(&nodename, name, fullname, NULL));
768 	}
769 
770 	/* memorize header contents prior to fixup */
771 	memmove(&header, n, sizeof(header));
772 
773 	if (n->left_is_relative) {
774 		CONFIRM(n->left <= (dns_rbtnode_t *) nodemax);
775 		n->left = getleft(n, rbt->mmap_location);
776 		n->left_is_relative = 0;
777 		CONFIRM(DNS_RBTNODE_VALID(n->left));
778 	} else
779 		CONFIRM(n->left == NULL);
780 
781 	if (n->right_is_relative) {
782 		CONFIRM(n->right <= (dns_rbtnode_t *) nodemax);
783 		n->right = getright(n, rbt->mmap_location);
784 		n->right_is_relative = 0;
785 		CONFIRM(DNS_RBTNODE_VALID(n->right));
786 	} else
787 		CONFIRM(n->right == NULL);
788 
789 	if (n->down_is_relative) {
790 		CONFIRM(n->down <= (dns_rbtnode_t *) nodemax);
791 		n->down = getdown(n, rbt->mmap_location);
792 		n->down_is_relative = 0;
793 		CONFIRM(n->down > (dns_rbtnode_t *) n);
794 		CONFIRM(DNS_RBTNODE_VALID(n->down));
795 	} else
796 		CONFIRM(n->down == NULL);
797 
798 	if (n->parent_is_relative) {
799 		CONFIRM(n->parent <= (dns_rbtnode_t *) nodemax);
800 		n->parent = getparent(n, rbt->mmap_location);
801 		n->parent_is_relative = 0;
802 		CONFIRM(n->parent < (dns_rbtnode_t *) n);
803 		CONFIRM(DNS_RBTNODE_VALID(n->parent));
804 	} else
805 		CONFIRM(n->parent == NULL);
806 
807 	if (n->data_is_relative) {
808 		CONFIRM(n->data <= (void *) filesize);
809 		n->data = getdata(n, rbt->mmap_location);
810 		n->data_is_relative = 0;
811 		CONFIRM(n->data > (void *) n);
812 	} else
813 		CONFIRM(n->data == NULL);
814 
815 	hash_node(rbt, n, fullname);
816 
817 	/* a change in the order (from left, right, down) will break hashing*/
818 	if (n->left != NULL)
819 		CHECK(treefix(rbt, base, filesize, n->left, name,
820 			      datafixer, fixer_arg, crc));
821 	if (n->right != NULL)
822 		CHECK(treefix(rbt, base, filesize, n->right, name,
823 			      datafixer, fixer_arg, crc));
824 	if (n->down != NULL)
825 		CHECK(treefix(rbt, base, filesize, n->down, fullname,
826 			      datafixer, fixer_arg, crc));
827 
828 	if (datafixer != NULL && n->data != NULL)
829 		CHECK(datafixer(n, base, filesize, fixer_arg, crc));
830 
831 	rbt->nodecount++;
832 	node_data = (unsigned char *) n + sizeof(dns_rbtnode_t);
833 	datasize = NODE_SIZE(n) - sizeof(dns_rbtnode_t);
834 
835 #ifdef DEBUG
836 	fprintf(stderr, "deserialize ");
837 	dns_name_print(&nodename, stderr);
838 	fprintf(stderr, "\n");
839 	hexdump("node header", &header,
840 		sizeof(dns_rbtnode_t));
841 	hexdump("node data", node_data, datasize);
842 #endif
843 	isc_crc64_update(crc, (const uint8_t *) &header,
844 			sizeof(dns_rbtnode_t));
845 	isc_crc64_update(crc, (const uint8_t *) node_data,
846 			datasize);
847 
848  cleanup:
849 	return (result);
850 }
851 
852 isc_result_t
853 dns_rbt_deserialize_tree(void *base_address, size_t filesize,
854 			 off_t header_offset, isc_mem_t *mctx,
855 			 dns_rbtdeleter_t deleter, void *deleter_arg,
856 			 dns_rbtdatafixer_t datafixer, void *fixer_arg,
857 			 dns_rbtnode_t **originp, dns_rbt_t **rbtp)
858 {
859 	isc_result_t result = ISC_R_SUCCESS;
860 	file_header_t *header;
861 	dns_rbt_t *rbt = NULL;
862 	uint64_t crc;
863 	unsigned int host_big_endian;
864 
865 	REQUIRE(originp == NULL || *originp == NULL);
866 	REQUIRE(rbtp != NULL && *rbtp == NULL);
867 
868 	isc_crc64_init(&crc);
869 
870 	CHECK(dns_rbt_create(mctx, deleter, deleter_arg, &rbt));
871 
872 	rbt->mmap_location = base_address;
873 
874 	header = (file_header_t *)((char *)base_address + header_offset);
875 	if (!match_header_version(header)) {
876 		result = ISC_R_INVALIDFILE;
877 		goto cleanup;
878 	}
879 
880 #ifdef DNS_RDATASET_FIXED
881 	if (header->rdataset_fixed != 1) {
882 		result = ISC_R_INVALIDFILE;
883 		goto cleanup;
884 	}
885 
886 #else
887 	if (header->rdataset_fixed != 0) {
888 		result = ISC_R_INVALIDFILE;
889 		goto cleanup;
890 	}
891 #endif
892 
893 	if (header->ptrsize != (uint32_t) sizeof(void *)) {
894 		result = ISC_R_INVALIDFILE;
895 		goto cleanup;
896 	}
897 
898 	host_big_endian = (1 == htonl(1));
899 	if (header->bigendian != host_big_endian) {
900 		result = ISC_R_INVALIDFILE;
901 		goto cleanup;
902 	}
903 
904 	/* Copy other data items from the header into our rbt. */
905 	rbt->root = (dns_rbtnode_t *)((char *)base_address +
906 				header_offset + header->first_node_offset);
907 
908 	if ((header->nodecount * sizeof(dns_rbtnode_t)) > filesize) {
909 		result = ISC_R_INVALIDFILE;
910 		goto cleanup;
911 	}
912 	rehash(rbt, header->nodecount);
913 
914 	CHECK(treefix(rbt, base_address, filesize, rbt->root,
915 		      dns_rootname, datafixer, fixer_arg, &crc));
916 
917 	isc_crc64_final(&crc);
918 #ifdef DEBUG
919 	hexdump("deserializing CRC", &crc, sizeof(crc));
920 #endif
921 
922 	/* Check file hash */
923 	if (header->crc != crc) {
924 		result = ISC_R_INVALIDFILE;
925 		goto cleanup;
926 	}
927 
928 	if (header->nodecount != rbt->nodecount) {
929 		result = ISC_R_INVALIDFILE;
930 		goto cleanup;
931 	}
932 
933 	fixup_uppernodes(rbt);
934 
935 	*rbtp = rbt;
936 	if (originp != NULL)
937 		*originp = rbt->root;
938 
939  cleanup:
940 	if (result != ISC_R_SUCCESS && rbt != NULL) {
941 		rbt->root = NULL;
942 		rbt->nodecount = 0;
943 		dns_rbt_destroy(&rbt);
944 	}
945 
946 	return (result);
947 }
948 
949 /*
950  * Initialize a red/black tree of trees.
951  */
952 isc_result_t
953 dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter,
954 	       void *deleter_arg, dns_rbt_t **rbtp)
955 {
956 	isc_result_t result;
957 	dns_rbt_t *rbt;
958 
959 	REQUIRE(mctx != NULL);
960 	REQUIRE(rbtp != NULL && *rbtp == NULL);
961 	REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
962 
963 	rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
964 	if (rbt == NULL)
965 		return (ISC_R_NOMEMORY);
966 
967 	rbt->mctx = NULL;
968 	isc_mem_attach(mctx, &rbt->mctx);
969 	rbt->data_deleter = deleter;
970 	rbt->deleter_arg = deleter_arg;
971 	rbt->root = NULL;
972 	rbt->nodecount = 0;
973 	rbt->hashtable = NULL;
974 	rbt->hashsize = 0;
975 	rbt->mmap_location = NULL;
976 
977 	result = inithash(rbt);
978 	if (result != ISC_R_SUCCESS) {
979 		isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
980 		return (result);
981 	}
982 
983 	rbt->magic = RBT_MAGIC;
984 
985 	*rbtp = rbt;
986 
987 	return (ISC_R_SUCCESS);
988 }
989 
990 /*
991  * Deallocate a red/black tree of trees.
992  */
993 void
994 dns_rbt_destroy(dns_rbt_t **rbtp) {
995 	RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
996 }
997 
998 isc_result_t
999 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
1000 	dns_rbt_t *rbt;
1001 
1002 	REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
1003 
1004 	rbt = *rbtp;
1005 
1006 	deletetreeflat(rbt, quantum, false, &rbt->root);
1007 	if (rbt->root != NULL)
1008 		return (ISC_R_QUOTA);
1009 
1010 	INSIST(rbt->nodecount == 0);
1011 
1012 	rbt->mmap_location = NULL;
1013 
1014 	if (rbt->hashtable != NULL)
1015 		isc_mem_put(rbt->mctx, rbt->hashtable,
1016 			    rbt->hashsize * sizeof(dns_rbtnode_t *));
1017 
1018 	rbt->magic = 0;
1019 
1020 	isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
1021 	*rbtp = NULL;
1022 	return (ISC_R_SUCCESS);
1023 }
1024 
1025 unsigned int
1026 dns_rbt_nodecount(dns_rbt_t *rbt) {
1027 
1028 	REQUIRE(VALID_RBT(rbt));
1029 
1030 	return (rbt->nodecount);
1031 }
1032 
1033 size_t
1034 dns_rbt_hashsize(dns_rbt_t *rbt) {
1035 
1036 	REQUIRE(VALID_RBT(rbt));
1037 
1038 	return (rbt->hashsize);
1039 }
1040 
1041 static inline isc_result_t
1042 chain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
1043 	   bool include_chain_end)
1044 {
1045 	dns_name_t nodename;
1046 	isc_result_t result = ISC_R_SUCCESS;
1047 	int i;
1048 
1049 	dns_name_init(&nodename, NULL);
1050 
1051 	if (include_chain_end && chain->end != NULL) {
1052 		NODENAME(chain->end, &nodename);
1053 		dns_name_copynf(&nodename, name);
1054 	} else
1055 		dns_name_reset(name);
1056 
1057 	for (i = (int)chain->level_count - 1; i >= 0; i--) {
1058 		NODENAME(chain->levels[i], &nodename);
1059 		result = dns_name_concatenate(name, &nodename, name, NULL);
1060 
1061 		if (result != ISC_R_SUCCESS)
1062 			return (result);
1063 	}
1064 	return (result);
1065 }
1066 
1067 static inline isc_result_t
1068 move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
1069 	do {
1070 		/*
1071 		 * Go as far right and then down as much as possible,
1072 		 * as long as the rightmost node has a down pointer.
1073 		 */
1074 		while (RIGHT(node) != NULL)
1075 			node = RIGHT(node);
1076 
1077 		if (DOWN(node) == NULL)
1078 			break;
1079 
1080 		ADD_LEVEL(chain, node);
1081 		node = DOWN(node);
1082 	} while (1);
1083 
1084 	chain->end = node;
1085 
1086 	return (ISC_R_SUCCESS);
1087 }
1088 
1089 /*
1090  * Add 'name' to tree, initializing its data pointer with 'data'.
1091  */
1092 
1093 isc_result_t
1094 dns_rbt_addnode(dns_rbt_t *rbt, const dns_name_t *name, dns_rbtnode_t **nodep) {
1095 	/*
1096 	 * Does this thing have too many variables or what?
1097 	 */
1098 	dns_rbtnode_t **root, *parent, *child, *current, *new_current;
1099 	dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
1100 	dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
1101 	dns_offsets_t current_offsets;
1102 	dns_namereln_t compared;
1103 	isc_result_t result = ISC_R_SUCCESS;
1104 	unsigned int level_count;
1105 	unsigned int common_labels;
1106 	unsigned int nlabels, hlabels;
1107 	int order;
1108 
1109 	REQUIRE(VALID_RBT(rbt));
1110 	REQUIRE(dns_name_isabsolute(name));
1111 	REQUIRE(nodep != NULL && *nodep == NULL);
1112 
1113 	/*
1114 	 * Dear future BIND developer,
1115 	 *
1116 	 * After you have tried attempting to optimize this routine by
1117 	 * using the hashtable and have realized your folly, please
1118 	 * append another cross ("X") below as a warning to the next
1119 	 * future BIND developer:
1120 	 *
1121 	 * Number of victim developers: X
1122 	 *
1123 	 * I wish the past developer had included such a notice.
1124 	 *
1125 	 * Long form: Unlike dns_rbt_findnode(), this function does not
1126 	 * lend itself to be optimized using the hashtable:
1127 	 *
1128 	 * 1. In the subtree where the insertion occurs, this function
1129 	 * needs to have the insertion point and the order where the
1130 	 * lookup terminated (i.e., at the insertion point where left or
1131 	 * right child is NULL). This cannot be determined from the
1132 	 * hashtable, so at least in that subtree, a BST O(log N) lookup
1133 	 * is necessary.
1134 	 *
1135 	 * 2. Our RBT nodes contain not only single labels but label
1136 	 * sequences to optimize space usage. So at every level, we have
1137 	 * to look for a match in the hashtable for all superdomains in
1138 	 * the rest of the name we're searching. This is an O(N)
1139 	 * operation at least, here N being the label size of name, each
1140 	 * of which is a hashtable lookup involving dns_name_equal()
1141 	 * comparisons.
1142 	 */
1143 
1144 	/*
1145 	 * Create a copy of the name so the original name structure is
1146 	 * not modified.
1147 	 */
1148 	add_name = dns_fixedname_initname(&fixedcopy);
1149 	INSIST(add_name != NULL);
1150 	dns_name_clone(name, add_name);
1151 
1152 	if (ISC_UNLIKELY(rbt->root == NULL)) {
1153 		result = create_node(rbt->mctx, add_name, &new_current);
1154 		if (result == ISC_R_SUCCESS) {
1155 			rbt->nodecount++;
1156 			new_current->is_root = 1;
1157 
1158 			UPPERNODE(new_current) = NULL;
1159 
1160 			rbt->root = new_current;
1161 			*nodep = new_current;
1162 			hash_node(rbt, new_current, name);
1163 		}
1164 		return (result);
1165 	}
1166 
1167 	level_count = 0;
1168 
1169 	prefix = dns_fixedname_initname(&fixedprefix);
1170 	suffix = dns_fixedname_initname(&fixedsuffix);
1171 
1172 	INSIST(prefix != NULL);
1173 	INSIST(suffix != NULL);
1174 
1175 	root = &rbt->root;
1176 	INSIST(IS_ROOT(*root));
1177 	parent = NULL;
1178 	current = NULL;
1179 	child = *root;
1180 	dns_name_init(&current_name, current_offsets);
1181 	new_name = dns_fixedname_initname(&fnewname);
1182 	nlabels = dns_name_countlabels(name);
1183 	hlabels = 0;
1184 
1185 	do {
1186 		current = child;
1187 
1188 		NODENAME(current, &current_name);
1189 		compared = dns_name_fullcompare(add_name, &current_name,
1190 						&order, &common_labels);
1191 
1192 		if (compared == dns_namereln_equal) {
1193 			*nodep = current;
1194 			result = ISC_R_EXISTS;
1195 			break;
1196 
1197 		}
1198 
1199 		if (compared == dns_namereln_none) {
1200 
1201 			if (order < 0) {
1202 				parent = current;
1203 				child = LEFT(current);
1204 
1205 			} else if (order > 0) {
1206 				parent = current;
1207 				child = RIGHT(current);
1208 
1209 			}
1210 
1211 		} else {
1212 			/*
1213 			 * This name has some suffix in common with the
1214 			 * name at the current node.  If the name at
1215 			 * the current node is shorter, that means the
1216 			 * new name should be in a subtree.  If the
1217 			 * name at the current node is longer, that means
1218 			 * the down pointer to this tree should point
1219 			 * to a new tree that has the common suffix, and
1220 			 * the non-common parts of these two names should
1221 			 * start a new tree.
1222 			 */
1223 			hlabels += common_labels;
1224 			if (compared == dns_namereln_subdomain) {
1225 				/*
1226 				 * All of the existing labels are in common,
1227 				 * so the new name is in a subtree.
1228 				 * Whack off the common labels for the
1229 				 * not-in-common part to be searched for
1230 				 * in the next level.
1231 				 */
1232 				dns_name_split(add_name, common_labels,
1233 					       add_name, NULL);
1234 
1235 				/*
1236 				 * Follow the down pointer (possibly NULL).
1237 				 */
1238 				root = &DOWN(current);
1239 
1240 				INSIST(*root == NULL ||
1241 				       (IS_ROOT(*root) &&
1242 					PARENT(*root) == current));
1243 
1244 				parent = NULL;
1245 				child = DOWN(current);
1246 
1247 				INSIST(level_count < DNS_RBT_LEVELBLOCK);
1248 				level_count++;
1249 			} else {
1250 				/*
1251 				 * The number of labels in common is fewer
1252 				 * than the number of labels at the current
1253 				 * node, so the current node must be adjusted
1254 				 * to have just the common suffix, and a down
1255 				 * pointer made to a new tree.
1256 				 */
1257 
1258 				INSIST(compared == dns_namereln_commonancestor
1259 				       || compared == dns_namereln_contains);
1260 
1261 				/*
1262 				 * Ensure the number of levels in the tree
1263 				 * does not exceed the number of logical
1264 				 * levels allowed by DNSSEC.
1265 				 *
1266 				 * XXXDCL need a better error result?
1267 				 */
1268 				if (level_count >= DNS_RBT_LEVELBLOCK) {
1269 					result = ISC_R_NOSPACE;
1270 					break;
1271 				}
1272 
1273 				/*
1274 				 * Split the name into two parts, a prefix
1275 				 * which is the not-in-common parts of the
1276 				 * two names and a suffix that is the common
1277 				 * parts of them.
1278 				 */
1279 				dns_name_split(&current_name, common_labels,
1280 					       prefix, suffix);
1281 				result = create_node(rbt->mctx, suffix,
1282 						     &new_current);
1283 
1284 				if (result != ISC_R_SUCCESS)
1285 					break;
1286 
1287 				/*
1288 				 * Reproduce the tree attributes of the
1289 				 * current node.
1290 				 */
1291 				new_current->is_root = current->is_root;
1292 				if (current->nsec == DNS_RBT_NSEC_HAS_NSEC)
1293 					new_current->nsec = DNS_RBT_NSEC_NORMAL;
1294 				else
1295 					new_current->nsec = current->nsec;
1296 				PARENT(new_current)  = PARENT(current);
1297 				LEFT(new_current)    = LEFT(current);
1298 				RIGHT(new_current)   = RIGHT(current);
1299 				COLOR(new_current)   = COLOR(current);
1300 
1301 				/*
1302 				 * Fix pointers that were to the current node.
1303 				 */
1304 				if (parent != NULL) {
1305 					if (LEFT(parent) == current)
1306 						LEFT(parent) = new_current;
1307 					else
1308 						RIGHT(parent) = new_current;
1309 				}
1310 				if (LEFT(new_current) != NULL)
1311 					PARENT(LEFT(new_current)) =
1312 						new_current;
1313 				if (RIGHT(new_current) != NULL)
1314 					PARENT(RIGHT(new_current)) =
1315 						new_current;
1316 				if (*root == current)
1317 					*root = new_current;
1318 
1319 				NAMELEN(current) = prefix->length;
1320 				OFFSETLEN(current) = prefix->labels;
1321 
1322 				/*
1323 				 * Set up the new root of the next level.
1324 				 * By definition it will not be the top
1325 				 * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
1326 				 */
1327 				current->is_root = 1;
1328 				PARENT(current) = new_current;
1329 				DOWN(new_current) = current;
1330 				root = &DOWN(new_current);
1331 
1332 				UPPERNODE(new_current) = UPPERNODE(current);
1333 				UPPERNODE(current) = new_current;
1334 
1335 				INSIST(level_count < DNS_RBT_LEVELBLOCK);
1336 				level_count++;
1337 
1338 				LEFT(current) = NULL;
1339 				RIGHT(current) = NULL;
1340 
1341 				MAKE_BLACK(current);
1342 				ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
1343 
1344 				rbt->nodecount++;
1345 				dns_name_getlabelsequence(name,
1346 							  nlabels - hlabels,
1347 							  hlabels, new_name);
1348 				hash_node(rbt, new_current, new_name);
1349 
1350 				if (common_labels ==
1351 				    dns_name_countlabels(add_name)) {
1352 					/*
1353 					 * The name has been added by pushing
1354 					 * the not-in-common parts down to
1355 					 * a new level.
1356 					 */
1357 					*nodep = new_current;
1358 					return (ISC_R_SUCCESS);
1359 
1360 				} else {
1361 					/*
1362 					 * The current node has no data,
1363 					 * because it is just a placeholder.
1364 					 * Its data pointer is already NULL
1365 					 * from create_node()), so there's
1366 					 * nothing more to do to it.
1367 					 */
1368 
1369 					/*
1370 					 * The not-in-common parts of the new
1371 					 * name will be inserted into the new
1372 					 * level following this loop (unless
1373 					 * result != ISC_R_SUCCESS, which
1374 					 * is tested after the loop ends).
1375 					 */
1376 					dns_name_split(add_name, common_labels,
1377 						       add_name, NULL);
1378 
1379 					break;
1380 				}
1381 
1382 			}
1383 
1384 		}
1385 
1386 	} while (ISC_LIKELY(child != NULL));
1387 
1388 	if (ISC_LIKELY(result == ISC_R_SUCCESS))
1389 		result = create_node(rbt->mctx, add_name, &new_current);
1390 
1391 	if (ISC_LIKELY(result == ISC_R_SUCCESS)) {
1392 		if (*root == NULL) {
1393 			UPPERNODE(new_current) = current;
1394 		} else {
1395 			UPPERNODE(new_current) = PARENT(*root);
1396 		}
1397 
1398 		addonlevel(new_current, current, order, root);
1399 		rbt->nodecount++;
1400 		*nodep = new_current;
1401 		hash_node(rbt, new_current, name);
1402 	}
1403 
1404 	return (result);
1405 }
1406 
1407 /*
1408  * Add a name to the tree of trees, associating it with some data.
1409  */
1410 isc_result_t
1411 dns_rbt_addname(dns_rbt_t *rbt, const dns_name_t *name, void *data) {
1412 	isc_result_t result;
1413 	dns_rbtnode_t *node;
1414 
1415 	REQUIRE(VALID_RBT(rbt));
1416 	REQUIRE(dns_name_isabsolute(name));
1417 
1418 	node = NULL;
1419 
1420 	result = dns_rbt_addnode(rbt, name, &node);
1421 
1422 	/*
1423 	 * dns_rbt_addnode will report the node exists even when
1424 	 * it does not have data associated with it, but the
1425 	 * dns_rbt_*name functions all behave depending on whether
1426 	 * there is data associated with a node.
1427 	 */
1428 	if (result == ISC_R_SUCCESS ||
1429 	    (result == ISC_R_EXISTS && DATA(node) == NULL)) {
1430 		DATA(node) = data;
1431 		result = ISC_R_SUCCESS;
1432 	}
1433 
1434 	return (result);
1435 }
1436 
1437 /*
1438  * Find the node for "name" in the tree of trees.
1439  */
1440 isc_result_t
1441 dns_rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname,
1442 		 dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
1443 		 unsigned int options, dns_rbtfindcallback_t callback,
1444 		 void *callback_arg)
1445 {
1446 	dns_rbtnode_t *current, *last_compared;
1447 	dns_rbtnodechain_t localchain;
1448 	dns_name_t *search_name, current_name, *callback_name;
1449 	dns_fixedname_t fixedcallbackname, fixedsearchname;
1450 	dns_namereln_t compared;
1451 	isc_result_t result, saved_result;
1452 	unsigned int common_labels;
1453 	unsigned int hlabels = 0;
1454 	int order;
1455 
1456 	REQUIRE(VALID_RBT(rbt));
1457 	REQUIRE(dns_name_isabsolute(name));
1458 	REQUIRE(node != NULL && *node == NULL);
1459 	REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
1460 		!=         (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
1461 
1462 	/*
1463 	 * If there is a chain it needs to appear to be in a sane state,
1464 	 * otherwise a chain is still needed to generate foundname and
1465 	 * callback_name.
1466 	 */
1467 	if (chain == NULL) {
1468 		options |= DNS_RBTFIND_NOPREDECESSOR;
1469 		chain = &localchain;
1470 		dns_rbtnodechain_init(chain, rbt->mctx);
1471 	} else
1472 		dns_rbtnodechain_reset(chain);
1473 
1474 	if (ISC_UNLIKELY(rbt->root == NULL))
1475 		return (ISC_R_NOTFOUND);
1476 
1477 	/*
1478 	 * Appease GCC about variables it incorrectly thinks are
1479 	 * possibly used uninitialized.
1480 	 */
1481 	compared = dns_namereln_none;
1482 	last_compared = NULL;
1483 	order = 0;
1484 
1485 	callback_name = dns_fixedname_initname(&fixedcallbackname);
1486 
1487 	/*
1488 	 * search_name is the name segment being sought in each tree level.
1489 	 * By using a fixedname, the search_name will definitely have offsets
1490 	 * for use by any splitting.
1491 	 * By using dns_name_clone, no name data should be copied thanks to
1492 	 * the lack of bitstring labels.
1493 	 */
1494 	search_name = dns_fixedname_initname(&fixedsearchname);
1495 	INSIST(search_name != NULL);
1496 	dns_name_clone(name, search_name);
1497 
1498 	dns_name_init(&current_name, NULL);
1499 
1500 	saved_result = ISC_R_SUCCESS;
1501 	current = rbt->root;
1502 
1503 	while (ISC_LIKELY(current != NULL)) {
1504 		NODENAME(current, &current_name);
1505 		compared = dns_name_fullcompare(search_name, &current_name,
1506 						&order, &common_labels);
1507 		/*
1508 		 * last_compared is used as a shortcut to start (or
1509 		 * continue rather) finding the stop-node of the search
1510 		 * when hashing was used (see much below in this
1511 		 * function).
1512 		 */
1513 		last_compared = current;
1514 
1515 		if (compared == dns_namereln_equal)
1516 			break;
1517 
1518 		if (compared == dns_namereln_none) {
1519 			/*
1520 			 * Here, current is pointing at a subtree root
1521 			 * node. We try to find a matching node using
1522 			 * the hashtable. We can get one of 3 results
1523 			 * here: (a) we locate the matching node, (b) we
1524 			 * find a node to which the current node has a
1525 			 * subdomain relation, (c) we fail to find (a)
1526 			 * or (b).
1527 			 */
1528 
1529 			dns_name_t hash_name;
1530 			dns_rbtnode_t *hnode;
1531 			dns_rbtnode_t *up_current;
1532 			unsigned int nlabels;
1533 			unsigned int tlabels = 1;
1534 			unsigned int hash;
1535 
1536 			/*
1537 			 * The case of current not being a subtree root,
1538 			 * that means a left or right pointer was
1539 			 * followed, only happens when the algorithm
1540 			 * fell through to the traditional binary search
1541 			 * because of a bitstring label.  Since we
1542 			 * dropped the bitstring support, this should
1543 			 * not happen.
1544 			 */
1545 			INSIST(IS_ROOT(current));
1546 
1547 			nlabels = dns_name_countlabels(search_name);
1548 
1549 			/*
1550 			 * current is the root of the current level, so
1551 			 * its parent is the same as its "up" pointer.
1552 			 */
1553 			up_current = PARENT(current);
1554 			dns_name_init(&hash_name, NULL);
1555 
1556 		hashagain:
1557 			/*
1558 			 * Compute the hash over the full absolute
1559 			 * name. Look for the smallest suffix match at
1560 			 * this tree level (hlevel), and then at every
1561 			 * iteration, look for the next smallest suffix
1562 			 * match (add another subdomain label to the
1563 			 * absolute name being hashed).
1564 			 */
1565 			dns_name_getlabelsequence(name,
1566 						  nlabels - tlabels,
1567 						  hlabels + tlabels,
1568 						  &hash_name);
1569 			hash = dns_name_fullhash(&hash_name, false);
1570 			dns_name_getlabelsequence(search_name,
1571 						  nlabels - tlabels,
1572 						  tlabels, &hash_name);
1573 
1574 			/*
1575 			 * Walk all the nodes in the hash bucket pointed
1576 			 * by the computed hash value.
1577 			 */
1578 			for (hnode = rbt->hashtable[hash % rbt->hashsize];
1579 			     hnode != NULL;
1580 			     hnode = hnode->hashnext)
1581 			{
1582 				dns_name_t hnode_name;
1583 
1584 				if (ISC_LIKELY(hash != HASHVAL(hnode)))
1585 					continue;
1586 				/*
1587 				 * This checks that the hashed label
1588 				 * sequence being looked up is at the
1589 				 * same tree level, so that we don't
1590 				 * match a labelsequence from some other
1591 				 * subdomain.
1592 				 */
1593 				if (ISC_LIKELY(get_upper_node(hnode) !=
1594 					       up_current))
1595 				{
1596 					continue;
1597 				}
1598 
1599 				dns_name_init(&hnode_name, NULL);
1600 				NODENAME(hnode, &hnode_name);
1601 				if (ISC_LIKELY(dns_name_equal(&hnode_name,
1602 							      &hash_name)))
1603 				{
1604 					break;
1605 				}
1606 			}
1607 
1608 			if (hnode != NULL) {
1609 				current = hnode;
1610 				/*
1611 				 * This is an optimization.  If hashing found
1612 				 * the right node, the next call to
1613 				 * dns_name_fullcompare() would obviously
1614 				 * return _equal or _subdomain.  Determine
1615 				 * which of those would be the case by
1616 				 * checking if the full name was hashed.  Then
1617 				 * make it look like dns_name_fullcompare
1618 				 * was called and jump to the right place.
1619 				 */
1620 				if (tlabels == nlabels) {
1621 					compared = dns_namereln_equal;
1622 					break;
1623 				} else {
1624 					common_labels = tlabels;
1625 					compared = dns_namereln_subdomain;
1626 					goto subdomain;
1627 				}
1628 			}
1629 
1630 			if (tlabels++ < nlabels)
1631 				goto hashagain;
1632 
1633 			/*
1634 			 * All of the labels have been tried against the hash
1635 			 * table.  Since we dropped the support of bitstring
1636 			 * labels, the name isn't in the table.
1637 			 */
1638 			current = NULL;
1639 			continue;
1640 		} else {
1641 			/*
1642 			 * The names have some common suffix labels.
1643 			 *
1644 			 * If the number in common are equal in length to
1645 			 * the current node's name length, then follow the
1646 			 * down pointer and search in the new tree.
1647 			 */
1648 			if (compared == dns_namereln_subdomain) {
1649  subdomain:
1650 				/*
1651 				 * Whack off the current node's common parts
1652 				 * for the name to search in the next level.
1653 				 */
1654 				dns_name_split(search_name, common_labels,
1655 					       search_name, NULL);
1656 				hlabels += common_labels;
1657 				/*
1658 				 * This might be the closest enclosing name.
1659 				 */
1660 				if (DATA(current) != NULL ||
1661 				    (options & DNS_RBTFIND_EMPTYDATA) != 0)
1662 					*node = current;
1663 
1664 				/*
1665 				 * Point the chain to the next level.   This
1666 				 * needs to be done before 'current' is pointed
1667 				 * there because the callback in the next
1668 				 * block of code needs the current 'current',
1669 				 * but in the event the callback requests that
1670 				 * the search be stopped then the
1671 				 * DNS_R_PARTIALMATCH code at the end of this
1672 				 * function needs the chain pointed to the
1673 				 * next level.
1674 				 */
1675 				ADD_LEVEL(chain, current);
1676 
1677 				/*
1678 				 * The caller may want to interrupt the
1679 				 * downward search when certain special nodes
1680 				 * are traversed.  If this is a special node,
1681 				 * the callback is used to learn what the
1682 				 * caller wants to do.
1683 				 */
1684 				if (callback != NULL &&
1685 				    FINDCALLBACK(current)) {
1686 					result = chain_name(chain,
1687 							    callback_name,
1688 							    false);
1689 					if (result != ISC_R_SUCCESS) {
1690 						dns_rbtnodechain_reset(chain);
1691 						return (result);
1692 					}
1693 
1694 					result = (callback)(current,
1695 							    callback_name,
1696 							    callback_arg);
1697 					if (result != DNS_R_CONTINUE) {
1698 						saved_result = result;
1699 						/*
1700 						 * Treat this node as if it
1701 						 * had no down pointer.
1702 						 */
1703 						current = NULL;
1704 						break;
1705 					}
1706 				}
1707 
1708 				/*
1709 				 * Finally, head to the next tree level.
1710 				 */
1711 				current = DOWN(current);
1712 			} else {
1713 				/*
1714 				 * Though there are labels in common, the
1715 				 * entire name at this node is not common
1716 				 * with the search name so the search
1717 				 * name does not exist in the tree.
1718 				 */
1719 				INSIST(compared == dns_namereln_commonancestor
1720 				       || compared == dns_namereln_contains);
1721 
1722 				current = NULL;
1723 			}
1724 		}
1725 	}
1726 
1727 	/*
1728 	 * If current is not NULL, NOEXACT is not disallowing exact matches,
1729 	 * and either the node has data or an empty node is ok, return
1730 	 * ISC_R_SUCCESS to indicate an exact match.
1731 	 */
1732 	if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
1733 	    (DATA(current) != NULL ||
1734 	     (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
1735 		/*
1736 		 * Found an exact match.
1737 		 */
1738 		chain->end = current;
1739 		chain->level_matches = chain->level_count;
1740 
1741 		if (foundname != NULL)
1742 			result = chain_name(chain, foundname, true);
1743 		else
1744 			result = ISC_R_SUCCESS;
1745 
1746 		if (result == ISC_R_SUCCESS) {
1747 			*node = current;
1748 			result = saved_result;
1749 		} else
1750 			*node = NULL;
1751 	} else {
1752 		/*
1753 		 * Did not find an exact match (or did not want one).
1754 		 */
1755 		if (*node != NULL) {
1756 			/*
1757 			 * ... but found a partially matching superdomain.
1758 			 * Unwind the chain to the partial match node
1759 			 * to set level_matches to the level above the node,
1760 			 * and then to derive the name.
1761 			 *
1762 			 * chain->level_count is guaranteed to be at least 1
1763 			 * here because by definition of finding a superdomain,
1764 			 * the chain is pointed to at least the first subtree.
1765 			 */
1766 			chain->level_matches = chain->level_count - 1;
1767 
1768 			while (chain->levels[chain->level_matches] != *node) {
1769 				INSIST(chain->level_matches > 0);
1770 				chain->level_matches--;
1771 			}
1772 
1773 			if (foundname != NULL) {
1774 				unsigned int saved_count = chain->level_count;
1775 
1776 				chain->level_count = chain->level_matches + 1;
1777 
1778 				result = chain_name(chain, foundname,
1779 						    false);
1780 
1781 				chain->level_count = saved_count;
1782 			} else
1783 				result = ISC_R_SUCCESS;
1784 
1785 			if (result == ISC_R_SUCCESS)
1786 				result = DNS_R_PARTIALMATCH;
1787 
1788 		} else
1789 			result = ISC_R_NOTFOUND;
1790 
1791 		if (current != NULL) {
1792 			/*
1793 			 * There was an exact match but either
1794 			 * DNS_RBTFIND_NOEXACT was set, or
1795 			 * DNS_RBTFIND_EMPTYDATA was set and the node had no
1796 			 * data.  A policy decision was made to set the
1797 			 * chain to the exact match, but this is subject
1798 			 * to change if it becomes apparent that something
1799 			 * else would be more useful.  It is important that
1800 			 * this case is handled here, because the predecessor
1801 			 * setting code below assumes the match was not exact.
1802 			 */
1803 			INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
1804 			       ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
1805 				DATA(current) == NULL));
1806 			chain->end = current;
1807 
1808 		} else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
1809 			/*
1810 			 * Ensure the chain points nowhere.
1811 			 */
1812 			chain->end = NULL;
1813 
1814 		} else {
1815 			/*
1816 			 * Since there was no exact match, the chain argument
1817 			 * needs to be pointed at the DNSSEC predecessor of
1818 			 * the search name.
1819 			 */
1820 			if (compared == dns_namereln_subdomain) {
1821 				/*
1822 				 * Attempted to follow a down pointer that was
1823 				 * NULL, which means the searched for name was
1824 				 * a subdomain of a terminal name in the tree.
1825 				 * Since there are no existing subdomains to
1826 				 * order against, the terminal name is the
1827 				 * predecessor.
1828 				 */
1829 				INSIST(chain->level_count > 0);
1830 				INSIST(chain->level_matches <
1831 				       chain->level_count);
1832 				chain->end =
1833 					chain->levels[--chain->level_count];
1834 
1835 			} else {
1836 				isc_result_t result2;
1837 
1838 				/*
1839 				 * Point current to the node that stopped
1840 				 * the search.
1841 				 *
1842 				 * With the hashing modification that has been
1843 				 * added to the algorithm, the stop node of a
1844 				 * standard binary search is not known.  So it
1845 				 * has to be found.  There is probably a more
1846 				 * clever way of doing this.
1847 				 *
1848 				 * The assignment of current to NULL when
1849 				 * the relationship is *not* dns_namereln_none,
1850 				 * even though it later gets set to the same
1851 				 * last_compared anyway, is simply to not push
1852 				 * the while loop in one more level of
1853 				 * indentation.
1854 				 */
1855 				if (compared == dns_namereln_none)
1856 					current = last_compared;
1857 				else
1858 					current = NULL;
1859 
1860 				while (current != NULL) {
1861 					NODENAME(current, &current_name);
1862 					compared = dns_name_fullcompare(
1863 								search_name,
1864 								&current_name,
1865 								&order,
1866 								&common_labels);
1867 					POST(compared);
1868 
1869 					last_compared = current;
1870 
1871 					/*
1872 					 * Standard binary search movement.
1873 					 */
1874 					if (order < 0)
1875 						current = LEFT(current);
1876 					else
1877 						current = RIGHT(current);
1878 
1879 				}
1880 
1881 				current = last_compared;
1882 
1883 				/*
1884 				 * Reached a point within a level tree that
1885 				 * positively indicates the name is not
1886 				 * present, but the stop node could be either
1887 				 * less than the desired name (order > 0) or
1888 				 * greater than the desired name (order < 0).
1889 				 *
1890 				 * If the stop node is less, it is not
1891 				 * necessarily the predecessor.  If the stop
1892 				 * node has a down pointer, then the real
1893 				 * predecessor is at the end of a level below
1894 				 * (not necessarily the next level).
1895 				 * Move down levels until the rightmost node
1896 				 * does not have a down pointer.
1897 				 *
1898 				 * When the stop node is greater, it is
1899 				 * the successor.  All the logic for finding
1900 				 * the predecessor is handily encapsulated
1901 				 * in dns_rbtnodechain_prev.  In the event
1902 				 * that the search name is less than anything
1903 				 * else in the tree, the chain is reset.
1904 				 * XXX DCL What is the best way for the caller
1905 				 *         to know that the search name has
1906 				 *         no predecessor?
1907 				 */
1908 
1909 
1910 				if (order > 0) {
1911 					if (DOWN(current) != NULL) {
1912 						ADD_LEVEL(chain, current);
1913 
1914 						result2 =
1915 						      move_chain_to_last(chain,
1916 								DOWN(current));
1917 
1918 						if (result2 != ISC_R_SUCCESS)
1919 							result = result2;
1920 					} else
1921 						/*
1922 						 * Ah, the pure and simple
1923 						 * case.  The stop node is the
1924 						 * predecessor.
1925 						 */
1926 						chain->end = current;
1927 
1928 				} else {
1929 					INSIST(order < 0);
1930 
1931 					chain->end = current;
1932 
1933 					result2 = dns_rbtnodechain_prev(chain,
1934 									NULL,
1935 									NULL);
1936 					if (result2 == ISC_R_SUCCESS ||
1937 					    result2 == DNS_R_NEWORIGIN)
1938 						;       /* Nothing. */
1939 					else if (result2 == ISC_R_NOMORE)
1940 						/*
1941 						 * There is no predecessor.
1942 						 */
1943 						dns_rbtnodechain_reset(chain);
1944 					else
1945 						result = result2;
1946 				}
1947 
1948 			}
1949 		}
1950 	}
1951 
1952 	ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
1953 
1954 	return (result);
1955 }
1956 
1957 /*
1958  * Get the data pointer associated with 'name'.
1959  */
1960 isc_result_t
1961 dns_rbt_findname(dns_rbt_t *rbt, const dns_name_t *name, unsigned int options,
1962 		 dns_name_t *foundname, void **data) {
1963 	dns_rbtnode_t *node = NULL;
1964 	isc_result_t result;
1965 
1966 	REQUIRE(data != NULL && *data == NULL);
1967 
1968 	result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
1969 				  options, NULL, NULL);
1970 
1971 	if (node != NULL &&
1972 	    (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
1973 		*data = DATA(node);
1974 	else
1975 		result = ISC_R_NOTFOUND;
1976 
1977 	return (result);
1978 }
1979 
1980 /*
1981  * Delete a name from the tree of trees.
1982  */
1983 isc_result_t
1984 dns_rbt_deletename(dns_rbt_t *rbt, const dns_name_t *name,
1985 		   bool recurse)
1986 {
1987 	dns_rbtnode_t *node = NULL;
1988 	isc_result_t result;
1989 
1990 	REQUIRE(VALID_RBT(rbt));
1991 	REQUIRE(dns_name_isabsolute(name));
1992 
1993 	/*
1994 	 * First, find the node.
1995 	 *
1996 	 * When searching, the name might not have an exact match:
1997 	 * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
1998 	 * elements of a tree, which would make layer 1 a single
1999 	 * node tree of "b.a.com" and layer 2 a three node tree of
2000 	 * a, b, and c.  Deleting a.com would find only a partial depth
2001 	 * match in the first layer.  Should it be a requirement that
2002 	 * that the name to be deleted have data?  For now, it is.
2003 	 *
2004 	 * ->dirty, ->locknum and ->references are ignored; they are
2005 	 * solely the province of rbtdb.c.
2006 	 */
2007 	result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
2008 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
2009 
2010 	if (result == ISC_R_SUCCESS) {
2011 		if (DATA(node) != NULL)
2012 			result = dns_rbt_deletenode(rbt, node, recurse);
2013 		else
2014 			result = ISC_R_NOTFOUND;
2015 
2016 	} else if (result == DNS_R_PARTIALMATCH)
2017 		result = ISC_R_NOTFOUND;
2018 
2019 	return (result);
2020 }
2021 
2022 /*
2023  * Remove a node from the tree of trees.
2024  *
2025  * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing
2026  * a sequence of additions to be deletions will not generally get the
2027  * tree back to the state it started in.  For example, if the addition
2028  * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level,
2029  * then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
2030  * restoring "a.b.c".  The RBT *used* to do this kind of rejoining, but it
2031  * turned out to be a bad idea because it could corrupt an active nodechain
2032  * that had "b.c" as one of its levels -- and the RBT has no idea what
2033  * nodechains are in use by callers, so it can't even *try* to helpfully
2034  * fix them up (which would probably be doomed to failure anyway).
2035  *
2036  * Similarly, it is possible to leave the tree in a state where a supposedly
2037  * deleted node still exists.  The first case of this is obvious; take
2038  * the tree which has "b.c" on one level, pointing to "a".  Now deleted "b.c".
2039  * It was just established in the previous paragraph why we can't pull "a"
2040  * back up to its parent level.  But what happens when "a" then gets deleted?
2041  * "b.c" is left hanging around without data or children.  This condition
2042  * is actually pretty easy to detect, but ... should it really be removed?
2043  * Is a chain pointing to it?  An iterator?  Who knows!  (Note that the
2044  * references structure member cannot be looked at because it is private to
2045  * rbtdb.)  This is ugly and makes me unhappy, but after hours of trying to
2046  * make it more aesthetically proper and getting nowhere, this is the way it
2047  * is going to stay until such time as it proves to be a *real* problem.
2048  *
2049  * Finally, for reference, note that the original routine that did node
2050  * joining was called join_nodes().  It has been excised, living now only
2051  * in the CVS history, but comments have been left behind that point to it just
2052  * in case someone wants to muck with this some more.
2053  *
2054  * The one positive aspect of all of this is that joining used to have a
2055  * case where it might fail.  Without trying to join, now this function always
2056  * succeeds. It still returns isc_result_t, though, so the API wouldn't change.
2057  */
2058 isc_result_t
2059 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, bool recurse)
2060 {
2061 	dns_rbtnode_t *parent;
2062 
2063 	REQUIRE(VALID_RBT(rbt));
2064 	REQUIRE(DNS_RBTNODE_VALID(node));
2065 	INSIST(rbt->nodecount != 0);
2066 
2067 	if (DOWN(node) != NULL) {
2068 		if (recurse) {
2069 			PARENT(DOWN(node)) = NULL;
2070 			deletetreeflat(rbt, 0, true, &DOWN(node));
2071 		} else {
2072 			if (DATA(node) != NULL && rbt->data_deleter != NULL)
2073 				rbt->data_deleter(DATA(node), rbt->deleter_arg);
2074 			DATA(node) = NULL;
2075 
2076 			/*
2077 			 * Since there is at least one node below this one and
2078 			 * no recursion was requested, the deletion is
2079 			 * complete.  The down node from this node might be all
2080 			 * by itself on a single level, so join_nodes() could
2081 			 * be used to collapse the tree (with all the caveats
2082 			 * of the comment at the start of this function).
2083 			 * But join_nodes() function has now been removed.
2084 			 */
2085 			return (ISC_R_SUCCESS);
2086 		}
2087 	}
2088 
2089 	/*
2090 	 * Note the node that points to the level of the node
2091 	 * that is being deleted.  If the deleted node is the
2092 	 * top level, parent will be set to NULL.
2093 	 */
2094 	parent = get_upper_node(node);
2095 
2096 	/*
2097 	 * This node now has no down pointer, so now it needs
2098 	 * to be removed from this level.
2099 	 */
2100 	deletefromlevel(node, parent == NULL ? &rbt->root : &DOWN(parent));
2101 
2102 	if (DATA(node) != NULL && rbt->data_deleter != NULL)
2103 		rbt->data_deleter(DATA(node), rbt->deleter_arg);
2104 
2105 	unhash_node(rbt, node);
2106 #if DNS_RBT_USEMAGIC
2107 	node->magic = 0;
2108 #endif
2109 	isc_refcount_destroy(&node->references);
2110 
2111 	freenode(rbt, &node);
2112 
2113 	/*
2114 	 * This function never fails.
2115 	 */
2116 	return (ISC_R_SUCCESS);
2117 }
2118 
2119 void
2120 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
2121 
2122 	REQUIRE(DNS_RBTNODE_VALID(node));
2123 	REQUIRE(name != NULL);
2124 	REQUIRE(name->offsets == NULL);
2125 
2126 	NODENAME(node, name);
2127 }
2128 
2129 isc_result_t
2130 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
2131 	dns_name_t current;
2132 	isc_result_t result;
2133 
2134 	REQUIRE(DNS_RBTNODE_VALID(node));
2135 	REQUIRE(name != NULL);
2136 	REQUIRE(name->buffer != NULL);
2137 
2138 	dns_name_init(&current, NULL);
2139 	dns_name_reset(name);
2140 
2141 	do {
2142 		INSIST(node != NULL);
2143 
2144 		NODENAME(node, &current);
2145 
2146 		result = dns_name_concatenate(name, &current, name, NULL);
2147 		if (result != ISC_R_SUCCESS)
2148 			break;
2149 
2150 		node = get_upper_node(node);
2151 	} while (! dns_name_isabsolute(name));
2152 
2153 	return (result);
2154 }
2155 
2156 char *
2157 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
2158 {
2159 	dns_fixedname_t fixedname;
2160 	dns_name_t *name;
2161 	isc_result_t result;
2162 
2163 	REQUIRE(DNS_RBTNODE_VALID(node));
2164 	REQUIRE(printname != NULL);
2165 
2166 	name = dns_fixedname_initname(&fixedname);
2167 	result = dns_rbt_fullnamefromnode(node, name);
2168 	if (result == ISC_R_SUCCESS)
2169 		dns_name_format(name, printname, size);
2170 	else
2171 		snprintf(printname, size, "<error building name: %s>",
2172 			 dns_result_totext(result));
2173 
2174 	return (printname);
2175 }
2176 
2177 static isc_result_t
2178 create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep) {
2179 	dns_rbtnode_t *node;
2180 	isc_region_t region;
2181 	unsigned int labels;
2182 	size_t nodelen;
2183 
2184 	REQUIRE(name->offsets != NULL);
2185 
2186 	dns_name_toregion(name, &region);
2187 	labels = dns_name_countlabels(name);
2188 	ENSURE(labels > 0);
2189 
2190 	/*
2191 	 * Allocate space for the node structure, the name, and the offsets.
2192 	 */
2193 	nodelen = sizeof(dns_rbtnode_t) + region.length + labels + 1;
2194 	node = (dns_rbtnode_t *)isc_mem_get(mctx, nodelen);
2195 	if (node == NULL)
2196 		return (ISC_R_NOMEMORY);
2197 	memset(node, 0, nodelen);
2198 
2199 	node->is_root = 0;
2200 	PARENT(node) = NULL;
2201 	RIGHT(node) = NULL;
2202 	LEFT(node) = NULL;
2203 	DOWN(node) = NULL;
2204 	DATA(node) = NULL;
2205 	node->is_mmapped = 0;
2206 	node->down_is_relative = 0;
2207 	node->left_is_relative = 0;
2208 	node->right_is_relative = 0;
2209 	node->parent_is_relative = 0;
2210 	node->data_is_relative = 0;
2211 	node->rpz = 0;
2212 
2213 	HASHNEXT(node) = NULL;
2214 	HASHVAL(node) = 0;
2215 
2216 	ISC_LINK_INIT(node, deadlink);
2217 
2218 	LOCKNUM(node) = 0;
2219 	WILD(node) = 0;
2220 	DIRTY(node) = 0;
2221 	isc_refcount_init(&node->references, 0);
2222 	node->find_callback = 0;
2223 	node->nsec = DNS_RBT_NSEC_NORMAL;
2224 
2225 	MAKE_BLACK(node);
2226 
2227 	/*
2228 	 * The following is stored to make reconstructing a name from the
2229 	 * stored value in the node easy:  the length of the name, the number
2230 	 * of labels, whether the name is absolute or not, the name itself,
2231 	 * and the name's offsets table.
2232 	 *
2233 	 * XXX RTH
2234 	 *      The offsets table could be made smaller by eliminating the
2235 	 *      first offset, which is always 0.  This requires changes to
2236 	 *      lib/dns/name.c.
2237 	 *
2238 	 * Note: OLDOFFSETLEN *must* be assigned *after* OLDNAMELEN is assigned
2239 	 * 	 as it uses OLDNAMELEN.
2240 	 */
2241 	OLDNAMELEN(node) = NAMELEN(node) = region.length;
2242 	OLDOFFSETLEN(node) = OFFSETLEN(node) = labels;
2243 	ATTRS(node) = name->attributes;
2244 
2245 	memmove(NAME(node), region.base, region.length);
2246 	memmove(OFFSETS(node), name->offsets, labels);
2247 
2248 #if DNS_RBT_USEMAGIC
2249 	node->magic = DNS_RBTNODE_MAGIC;
2250 #endif
2251 	*nodep = node;
2252 
2253 	return (ISC_R_SUCCESS);
2254 }
2255 
2256 /*
2257  * Add a node to the hash table
2258  */
2259 static inline void
2260 hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, const dns_name_t *name) {
2261 	unsigned int hash;
2262 
2263 	REQUIRE(name != NULL);
2264 
2265 	HASHVAL(node) = dns_name_fullhash(name, false);
2266 
2267 	hash = HASHVAL(node) % rbt->hashsize;
2268 	HASHNEXT(node) = rbt->hashtable[hash];
2269 
2270 	rbt->hashtable[hash] = node;
2271 }
2272 
2273 /*
2274  * Initialize hash table
2275  */
2276 static isc_result_t
2277 inithash(dns_rbt_t *rbt) {
2278 	unsigned int bytes;
2279 
2280 	rbt->hashsize = RBT_HASH_SIZE;
2281 	bytes = (unsigned int)rbt->hashsize * sizeof(dns_rbtnode_t *);
2282 	rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
2283 
2284 	if (rbt->hashtable == NULL)
2285 		return (ISC_R_NOMEMORY);
2286 
2287 	memset(rbt->hashtable, 0, bytes);
2288 
2289 	return (ISC_R_SUCCESS);
2290 }
2291 
2292 /*
2293  * Rebuild the hashtable to reduce the load factor
2294  */
2295 static void
2296 rehash(dns_rbt_t *rbt, unsigned int newcount) {
2297 	unsigned int oldsize;
2298 	dns_rbtnode_t **oldtable;
2299 	dns_rbtnode_t *node;
2300 	dns_rbtnode_t *nextnode;
2301 	unsigned int hash;
2302 	unsigned int i;
2303 
2304 	oldsize = (unsigned int)rbt->hashsize;
2305 	oldtable = rbt->hashtable;
2306 	do {
2307 		INSIST((rbt->hashsize * 2 + 1) > rbt->hashsize);
2308 		rbt->hashsize = rbt->hashsize * 2 + 1;
2309 	} while (newcount >= (rbt->hashsize * 3));
2310 	rbt->hashtable = isc_mem_get(rbt->mctx,
2311 				     rbt->hashsize * sizeof(dns_rbtnode_t *));
2312 	if (rbt->hashtable == NULL) {
2313 		rbt->hashtable = oldtable;
2314 		rbt->hashsize = oldsize;
2315 		return;
2316 	}
2317 
2318 	for (i = 0; i < rbt->hashsize; i++)
2319 		rbt->hashtable[i] = NULL;
2320 
2321 	for (i = 0; i < oldsize; i++) {
2322 		for (node = oldtable[i]; node != NULL; node = nextnode) {
2323 			hash = HASHVAL(node) % rbt->hashsize;
2324 			nextnode = HASHNEXT(node);
2325 			HASHNEXT(node) = rbt->hashtable[hash];
2326 			rbt->hashtable[hash] = node;
2327 		}
2328 	}
2329 
2330 	isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
2331 }
2332 
2333 /*
2334  * Add a node to the hash table. Rehash the hashtable if the node count
2335  * rises above a critical level.
2336  */
2337 static inline void
2338 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, const dns_name_t *name) {
2339 	REQUIRE(DNS_RBTNODE_VALID(node));
2340 
2341 	if (rbt->nodecount >= (rbt->hashsize * 3))
2342 		rehash(rbt, rbt->nodecount);
2343 
2344 	hash_add_node(rbt, node, name);
2345 }
2346 
2347 /*
2348  * Remove a node from the hash table
2349  */
2350 static inline void
2351 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
2352 	unsigned int bucket;
2353 	dns_rbtnode_t *bucket_node;
2354 
2355 	REQUIRE(DNS_RBTNODE_VALID(node));
2356 
2357 	bucket = HASHVAL(node) % rbt->hashsize;
2358 	bucket_node = rbt->hashtable[bucket];
2359 
2360 	if (bucket_node == node) {
2361 		rbt->hashtable[bucket] = HASHNEXT(node);
2362 	} else {
2363 		while (HASHNEXT(bucket_node) != node) {
2364 			INSIST(HASHNEXT(bucket_node) != NULL);
2365 			bucket_node = HASHNEXT(bucket_node);
2366 		}
2367 		HASHNEXT(bucket_node) = HASHNEXT(node);
2368 	}
2369 }
2370 
2371 static inline void
2372 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
2373 	dns_rbtnode_t *child;
2374 
2375 	REQUIRE(DNS_RBTNODE_VALID(node));
2376 	REQUIRE(rootp != NULL);
2377 
2378 	child = RIGHT(node);
2379 	INSIST(child != NULL);
2380 
2381 	RIGHT(node) = LEFT(child);
2382 	if (LEFT(child) != NULL)
2383 		PARENT(LEFT(child)) = node;
2384 	LEFT(child) = node;
2385 
2386 	PARENT(child) = PARENT(node);
2387 
2388 	if (IS_ROOT(node)) {
2389 		*rootp = child;
2390 		child->is_root = 1;
2391 		node->is_root = 0;
2392 
2393 	} else {
2394 		if (LEFT(PARENT(node)) == node)
2395 			LEFT(PARENT(node)) = child;
2396 		else
2397 			RIGHT(PARENT(node)) = child;
2398 	}
2399 
2400 	PARENT(node) = child;
2401 }
2402 
2403 static inline void
2404 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
2405 	dns_rbtnode_t *child;
2406 
2407 	REQUIRE(DNS_RBTNODE_VALID(node));
2408 	REQUIRE(rootp != NULL);
2409 
2410 	child = LEFT(node);
2411 	INSIST(child != NULL);
2412 
2413 	LEFT(node) = RIGHT(child);
2414 	if (RIGHT(child) != NULL)
2415 		PARENT(RIGHT(child)) = node;
2416 	RIGHT(child) = node;
2417 
2418 	PARENT(child) = PARENT(node);
2419 
2420 	if (IS_ROOT(node)) {
2421 		*rootp = child;
2422 		child->is_root = 1;
2423 		node->is_root = 0;
2424 
2425 	} else {
2426 		if (LEFT(PARENT(node)) == node)
2427 			LEFT(PARENT(node)) = child;
2428 		else
2429 			RIGHT(PARENT(node)) = child;
2430 	}
2431 
2432 	PARENT(node) = child;
2433 }
2434 
2435 /*
2436  * This is the real workhorse of the insertion code, because it does the
2437  * true red/black tree on a single level.
2438  */
2439 static void
2440 addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
2441 	   dns_rbtnode_t **rootp)
2442 {
2443 	dns_rbtnode_t *child, *root, *parent, *grandparent;
2444 	dns_name_t add_name, current_name;
2445 	dns_offsets_t add_offsets, current_offsets;
2446 
2447 	REQUIRE(rootp != NULL);
2448 	REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
2449 		RIGHT(node) == NULL);
2450 	REQUIRE(current != NULL);
2451 
2452 	root = *rootp;
2453 	if (root == NULL) {
2454 		/*
2455 		 * First node of a level.
2456 		 */
2457 		MAKE_BLACK(node);
2458 		node->is_root = 1;
2459 		PARENT(node) = current;
2460 		*rootp = node;
2461 		return;
2462 	}
2463 
2464 	child = root;
2465 	POST(child);
2466 
2467 	dns_name_init(&add_name, add_offsets);
2468 	NODENAME(node, &add_name);
2469 
2470 	dns_name_init(&current_name, current_offsets);
2471 	NODENAME(current, &current_name);
2472 
2473 	if (order < 0) {
2474 		INSIST(LEFT(current) == NULL);
2475 		LEFT(current) = node;
2476 	} else {
2477 		INSIST(RIGHT(current) == NULL);
2478 		RIGHT(current) = node;
2479 	}
2480 
2481 	INSIST(PARENT(node) == NULL);
2482 	PARENT(node) = current;
2483 
2484 	MAKE_RED(node);
2485 
2486 	while (node != root && IS_RED(PARENT(node))) {
2487 		/*
2488 		 * XXXDCL could do away with separate parent and grandparent
2489 		 * variables.  They are vestiges of the days before parent
2490 		 * pointers.  However, they make the code a little clearer.
2491 		 */
2492 
2493 		parent = PARENT(node);
2494 		grandparent = PARENT(parent);
2495 
2496 		if (parent == LEFT(grandparent)) {
2497 			child = RIGHT(grandparent);
2498 			if (child != NULL && IS_RED(child)) {
2499 				MAKE_BLACK(parent);
2500 				MAKE_BLACK(child);
2501 				MAKE_RED(grandparent);
2502 				node = grandparent;
2503 			} else {
2504 				if (node == RIGHT(parent)) {
2505 					rotate_left(parent, &root);
2506 					node = parent;
2507 					parent = PARENT(node);
2508 					grandparent = PARENT(parent);
2509 				}
2510 				MAKE_BLACK(parent);
2511 				MAKE_RED(grandparent);
2512 				rotate_right(grandparent, &root);
2513 			}
2514 		} else {
2515 			child = LEFT(grandparent);
2516 			if (child != NULL && IS_RED(child)) {
2517 				MAKE_BLACK(parent);
2518 				MAKE_BLACK(child);
2519 				MAKE_RED(grandparent);
2520 				node = grandparent;
2521 			} else {
2522 				if (node == LEFT(parent)) {
2523 					rotate_right(parent, &root);
2524 					node = parent;
2525 					parent = PARENT(node);
2526 					grandparent = PARENT(parent);
2527 				}
2528 				MAKE_BLACK(parent);
2529 				MAKE_RED(grandparent);
2530 				rotate_left(grandparent, &root);
2531 			}
2532 		}
2533 	}
2534 
2535 	MAKE_BLACK(root);
2536 	ENSURE(IS_ROOT(root));
2537 	*rootp = root;
2538 
2539 	return;
2540 }
2541 
2542 /*
2543  * This is the real workhorse of the deletion code, because it does the
2544  * true red/black tree on a single level.
2545  */
2546 static void
2547 deletefromlevel(dns_rbtnode_t *item, dns_rbtnode_t **rootp) {
2548 	dns_rbtnode_t *child, *sibling, *parent;
2549 	dns_rbtnode_t *successor;
2550 
2551 	REQUIRE(item != NULL);
2552 
2553 	/*
2554 	 * Verify that the parent history is (apparently) correct.
2555 	 */
2556 	INSIST((IS_ROOT(item) && *rootp == item) ||
2557 	       (! IS_ROOT(item) &&
2558 		(LEFT(PARENT(item)) == item ||
2559 		 RIGHT(PARENT(item)) == item)));
2560 
2561 	child = NULL;
2562 
2563 	if (LEFT(item) == NULL) {
2564 		if (RIGHT(item) == NULL) {
2565 			if (IS_ROOT(item)) {
2566 				/*
2567 				 * This is the only item in the tree.
2568 				 */
2569 				*rootp = NULL;
2570 				return;
2571 			}
2572 		} else
2573 			/*
2574 			 * This node has one child, on the right.
2575 			 */
2576 			child = RIGHT(item);
2577 
2578 	} else if (RIGHT(item) == NULL)
2579 		/*
2580 		 * This node has one child, on the left.
2581 		 */
2582 		child = LEFT(item);
2583 	else {
2584 		dns_rbtnode_t holder, *tmp = &holder;
2585 
2586 		/*
2587 		 * This node has two children, so it cannot be directly
2588 		 * deleted.  Find its immediate in-order successor and
2589 		 * move it to this location, then do the deletion at the
2590 		 * old site of the successor.
2591 		 */
2592 		successor = RIGHT(item);
2593 		while (LEFT(successor) != NULL)
2594 			successor = LEFT(successor);
2595 
2596 		/*
2597 		 * The successor cannot possibly have a left child;
2598 		 * if there is any child, it is on the right.
2599 		 */
2600 		if (RIGHT(successor) != NULL)
2601 			child = RIGHT(successor);
2602 
2603 		/*
2604 		 * Swap the two nodes; it would be simpler to just replace
2605 		 * the value being deleted with that of the successor,
2606 		 * but this rigamarole is done so the caller has complete
2607 		 * control over the pointers (and memory allocation) of
2608 		 * all of nodes.  If just the key value were removed from
2609 		 * the tree, the pointer to the node would be unchanged.
2610 		 */
2611 
2612 		/*
2613 		 * First, put the successor in the tree location of the
2614 		 * node to be deleted.  Save its existing tree pointer
2615 		 * information, which will be needed when linking up
2616 		 * delete to the successor's old location.
2617 		 */
2618 		memmove(tmp, successor, sizeof(dns_rbtnode_t));
2619 
2620 		if (IS_ROOT(item)) {
2621 			*rootp = successor;
2622 			successor->is_root = true;
2623 			item->is_root = false;
2624 
2625 		} else
2626 			if (LEFT(PARENT(item)) == item)
2627 				LEFT(PARENT(item)) = successor;
2628 			else
2629 				RIGHT(PARENT(item)) = successor;
2630 
2631 		PARENT(successor) = PARENT(item);
2632 		LEFT(successor)   = LEFT(item);
2633 		RIGHT(successor)  = RIGHT(item);
2634 		COLOR(successor)  = COLOR(item);
2635 
2636 		if (LEFT(successor) != NULL)
2637 			PARENT(LEFT(successor)) = successor;
2638 		if (RIGHT(successor) != successor)
2639 			PARENT(RIGHT(successor)) = successor;
2640 
2641 		/*
2642 		 * Now relink the node to be deleted into the
2643 		 * successor's previous tree location.  PARENT(tmp)
2644 		 * is the successor's original parent.
2645 		 */
2646 		INSIST(! IS_ROOT(item));
2647 
2648 		if (PARENT(tmp) == item) {
2649 			/*
2650 			 * Node being deleted was successor's parent.
2651 			 */
2652 			RIGHT(successor) = item;
2653 			PARENT(item) = successor;
2654 
2655 		} else {
2656 			LEFT(PARENT(tmp)) = item;
2657 			PARENT(item) = PARENT(tmp);
2658 		}
2659 
2660 		/*
2661 		 * Original location of successor node has no left.
2662 		 */
2663 		LEFT(item)   = NULL;
2664 		RIGHT(item)  = RIGHT(tmp);
2665 		COLOR(item)  = COLOR(tmp);
2666 	}
2667 
2668 	/*
2669 	 * Remove the node by removing the links from its parent.
2670 	 */
2671 	if (! IS_ROOT(item)) {
2672 		if (LEFT(PARENT(item)) == item)
2673 			LEFT(PARENT(item)) = child;
2674 		else
2675 			RIGHT(PARENT(item)) = child;
2676 
2677 		if (child != NULL)
2678 			PARENT(child) = PARENT(item);
2679 
2680 	} else {
2681 		/*
2682 		 * This is the root being deleted, and at this point
2683 		 * it is known to have just one child.
2684 		 */
2685 		*rootp = child;
2686 		child->is_root = 1;
2687 		PARENT(child) = PARENT(item);
2688 	}
2689 
2690 	/*
2691 	 * Fix color violations.
2692 	 */
2693 	if (IS_BLACK(item)) {
2694 		/* cppcheck-suppress nullPointerRedundantCheck symbolName=item */
2695 		parent = PARENT(item);
2696 
2697 		while (child != *rootp && IS_BLACK(child)) {
2698 			INSIST(child == NULL || ! IS_ROOT(child));
2699 
2700 			if (LEFT(parent) == child) {
2701 				sibling = RIGHT(parent);
2702 
2703 				if (IS_RED(sibling)) {
2704 					MAKE_BLACK(sibling);
2705 					MAKE_RED(parent);
2706 					rotate_left(parent, rootp);
2707 					sibling = RIGHT(parent);
2708 				}
2709 
2710 				INSIST(sibling != NULL);
2711 
2712 				/* cppcheck-suppress nullPointerRedundantCheck symbolName=sibling */
2713 				if (IS_BLACK(LEFT(sibling)) &&
2714 				    IS_BLACK(RIGHT(sibling))) {
2715 					MAKE_RED(sibling);
2716 					child = parent;
2717 
2718 				} else {
2719 
2720 					if (IS_BLACK(RIGHT(sibling))) {
2721 						MAKE_BLACK(LEFT(sibling));
2722 						MAKE_RED(sibling);
2723 						rotate_right(sibling, rootp);
2724 						sibling = RIGHT(parent);
2725 					}
2726 
2727 					COLOR(sibling) = COLOR(parent);
2728 					MAKE_BLACK(parent);
2729 					INSIST(RIGHT(sibling) != NULL);
2730 					MAKE_BLACK(RIGHT(sibling));
2731 					rotate_left(parent, rootp);
2732 					child = *rootp;
2733 				}
2734 
2735 			} else {
2736 				/*
2737 				 * Child is parent's right child.
2738 				 * Everything is done the same as above,
2739 				 * except mirrored.
2740 				 */
2741 				sibling = LEFT(parent);
2742 
2743 				if (IS_RED(sibling)) {
2744 					MAKE_BLACK(sibling);
2745 					MAKE_RED(parent);
2746 					rotate_right(parent, rootp);
2747 					sibling = LEFT(parent);
2748 				}
2749 
2750 				INSIST(sibling != NULL);
2751 
2752 				/* cppcheck-suppress nullPointerRedundantCheck symbolName=sibling */
2753 				if (IS_BLACK(LEFT(sibling)) &&
2754 				    IS_BLACK(RIGHT(sibling))) {
2755 					MAKE_RED(sibling);
2756 					child = parent;
2757 
2758 				} else {
2759 					if (IS_BLACK(LEFT(sibling))) {
2760 						MAKE_BLACK(RIGHT(sibling));
2761 						MAKE_RED(sibling);
2762 						rotate_left(sibling, rootp);
2763 						sibling = LEFT(parent);
2764 					}
2765 
2766 					COLOR(sibling) = COLOR(parent);
2767 					MAKE_BLACK(parent);
2768 					INSIST(LEFT(sibling) != NULL);
2769 					MAKE_BLACK(LEFT(sibling));
2770 					rotate_right(parent, rootp);
2771 					child = *rootp;
2772 				}
2773 			}
2774 
2775 			parent = PARENT(child);
2776 		}
2777 
2778 		if (IS_RED(child))
2779 			MAKE_BLACK(child);
2780 	}
2781 }
2782 
2783 static void
2784 freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep) {
2785 	dns_rbtnode_t *node = *nodep;
2786 
2787 	if (node->is_mmapped == 0) {
2788 		isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
2789 	}
2790 	*nodep = NULL;
2791 
2792 	rbt->nodecount--;
2793 }
2794 
2795 static void
2796 deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, bool unhash,
2797 	       dns_rbtnode_t **nodep)
2798 {
2799 	dns_rbtnode_t *root = *nodep;
2800 
2801 	while (root != NULL) {
2802 		/*
2803 		 * If there is a left, right or down node, walk into it
2804 		 * and iterate.
2805 		 */
2806 		if (LEFT(root) != NULL) {
2807 			dns_rbtnode_t *node = root;
2808 			root = LEFT(root);
2809 			LEFT(node) = NULL;
2810 		} else if (RIGHT(root) != NULL) {
2811 			dns_rbtnode_t *node = root;
2812 			root = RIGHT(root);
2813 			RIGHT(node) = NULL;
2814 		} else if (DOWN(root) != NULL) {
2815 			dns_rbtnode_t *node = root;
2816 			root = DOWN(root);
2817 			DOWN(node) = NULL;
2818 		} else {
2819 			/*
2820 			 * There are no left, right or down nodes, so we
2821 			 * can free this one and go back to its parent.
2822 			 */
2823 			dns_rbtnode_t *node = root;
2824 			root = PARENT(root);
2825 
2826 			if (DATA(node) != NULL && rbt->data_deleter != NULL)
2827 				rbt->data_deleter(DATA(node),
2828 						  rbt->deleter_arg);
2829 			if (unhash)
2830 				unhash_node(rbt, node);
2831 			/*
2832 			 * Note: we don't call unhash_node() here as we
2833 			 * are destroying the complete RBT tree.
2834 			 */
2835 #if DNS_RBT_USEMAGIC
2836 			node->magic = 0;
2837 #endif
2838 			freenode(rbt, &node);
2839 			if (quantum != 0 && --quantum == 0)
2840 				break;
2841 		}
2842 	}
2843 
2844 	*nodep = root;
2845 }
2846 
2847 static size_t
2848 getheight_helper(dns_rbtnode_t *node) {
2849 	size_t dl, dr;
2850 	size_t this_height, down_height;
2851 
2852 	if (node == NULL)
2853 		return (0);
2854 
2855 	dl = getheight_helper(LEFT(node));
2856 	dr = getheight_helper(RIGHT(node));
2857 
2858 	this_height = ISC_MAX(dl + 1, dr + 1);
2859 	down_height = getheight_helper(DOWN(node));
2860 
2861 	return (ISC_MAX(this_height, down_height));
2862 }
2863 
2864 size_t
2865 dns__rbt_getheight(dns_rbt_t *rbt) {
2866 	return (getheight_helper(rbt->root));
2867 }
2868 
2869 static bool
2870 check_properties_helper(dns_rbtnode_t *node) {
2871 	if (node == NULL)
2872 		return (true);
2873 
2874 	if (IS_RED(node)) {
2875 		/* Root nodes must be BLACK. */
2876 		if (IS_ROOT(node))
2877 			return (false);
2878 
2879 		/* Both children of RED nodes must be BLACK. */
2880 		if (IS_RED(LEFT(node)) || IS_RED(RIGHT(node)))
2881 			return (false);
2882 	}
2883 
2884 	/* cppcheck-suppress nullPointerRedundantCheck symbolName=node */
2885 	if ((DOWN(node) != NULL) && (!IS_ROOT(DOWN(node))))
2886 		return (false);
2887 
2888 	if (IS_ROOT(node)) {
2889 		if ((PARENT(node) != NULL) &&
2890 		    (DOWN(PARENT(node)) != node))
2891 			return (false);
2892 
2893 		if (get_upper_node(node) != PARENT(node))
2894 			return (false);
2895 	}
2896 
2897 	/* If node is assigned to the down_ pointer of its parent, it is
2898 	 * a subtree root and must have the flag set.
2899 	 */
2900 	if (((!PARENT(node)) ||
2901 	     (DOWN(PARENT(node)) == node)) &&
2902 	    (!IS_ROOT(node)))
2903 	{
2904 		return (false);
2905 	}
2906 
2907 	/* Repeat tests with this node's children. */
2908 	return (check_properties_helper(LEFT(node)) &&
2909 		check_properties_helper(RIGHT(node)) &&
2910 		check_properties_helper(DOWN(node)));
2911 }
2912 
2913 static bool
2914 check_black_distance_helper(dns_rbtnode_t *node, size_t *distance) {
2915 	size_t dl, dr, dd;
2916 
2917 	if (node == NULL) {
2918 		*distance = 1;
2919 		return (true);
2920 	}
2921 
2922 	/* cppcheck-suppress nullPointerRedundantCheck symbolName=node */
2923 	if (!check_black_distance_helper(LEFT(node), &dl))
2924 		return (false);
2925 
2926 	/* cppcheck-suppress nullPointerRedundantCheck symbolName=node */
2927 	if (!check_black_distance_helper(RIGHT(node), &dr))
2928 		return (false);
2929 
2930 	/* cppcheck-suppress nullPointerRedundantCheck symbolName=node */
2931 	if (!check_black_distance_helper(DOWN(node), &dd))
2932 		return (false);
2933 
2934 	/* Left and right side black node counts must match. */
2935 	if (dl != dr)
2936 		return (false);
2937 
2938 	if (IS_BLACK(node))
2939 		dl++;
2940 
2941 	*distance = dl;
2942 
2943 	return (true);
2944 }
2945 
2946 bool
2947 dns__rbt_checkproperties(dns_rbt_t *rbt) {
2948 	size_t dd;
2949 
2950 	if (!check_properties_helper(rbt->root))
2951 		return (false);
2952 
2953 	/* Path from a given node to all its leaves must contain the
2954 	 * same number of BLACK child nodes. This is done separately
2955 	 * here instead of inside check_properties_helper() as
2956 	 * it would take (n log n) complexity otherwise.
2957 	 */
2958 	return (check_black_distance_helper(rbt->root, &dd));
2959 }
2960 
2961 static void
2962 dns_rbt_indent(FILE *f, int depth) {
2963 	int i;
2964 
2965 	fprintf(f, "%4d ", depth);
2966 
2967 	for (i = 0; i < depth; i++)
2968 		fprintf(f, "- ");
2969 }
2970 
2971 void
2972 dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f) {
2973 
2974 	if (n == NULL) {
2975 		fprintf(f, "Null node\n");
2976 		return;
2977 	}
2978 
2979 	fprintf(f, "Node info for nodename: ");
2980 	printnodename(n, true, f);
2981 	fprintf(f, "\n");
2982 
2983 	fprintf(f, "n = %p\n", n);
2984 
2985 	fprintf(f, "Relative pointers: %s%s%s%s%s\n",
2986 			(n->parent_is_relative == 1 ? " P" : ""),
2987 			(n->right_is_relative == 1 ? " R" : ""),
2988 			(n->left_is_relative == 1 ? " L" : ""),
2989 			(n->down_is_relative == 1 ? " D" : ""),
2990 			(n->data_is_relative == 1 ? " T" : ""));
2991 
2992 	fprintf(f, "node lock address = %u\n", n->locknum);
2993 
2994 	fprintf(f, "Parent: %p\n", n->parent);
2995 	fprintf(f, "Right: %p\n", n->right);
2996 	fprintf(f, "Left: %p\n", n->left);
2997 	fprintf(f, "Down: %p\n", n->down);
2998 	fprintf(f, "Data: %p\n", n->data);
2999 }
3000 
3001 static void
3002 printnodename(dns_rbtnode_t *node, bool quoted, FILE *f) {
3003 	isc_region_t r;
3004 	dns_name_t name;
3005 	char buffer[DNS_NAME_FORMATSIZE];
3006 	dns_offsets_t offsets;
3007 
3008 	r.length = NAMELEN(node);
3009 	r.base = NAME(node);
3010 
3011 	dns_name_init(&name, offsets);
3012 	dns_name_fromregion(&name, &r);
3013 
3014 	dns_name_format(&name, buffer, sizeof(buffer));
3015 
3016 	if (quoted)
3017 		fprintf(f, "\"%s\"", buffer);
3018 	else
3019 		fprintf(f, "%s", buffer);
3020 }
3021 
3022 static void
3023 print_text_helper(dns_rbtnode_t *root, dns_rbtnode_t *parent,
3024 		  int depth, const char *direction,
3025 		  void (*data_printer)(FILE *, void *), FILE *f)
3026 {
3027 	dns_rbt_indent(f, depth);
3028 
3029 	if (root != NULL) {
3030 		printnodename(root, true, f);
3031 		/*
3032 		 * Don't use IS_RED(root) as it tests for 'root != NULL'
3033 		 * and cppcheck produces false positives.
3034 		 */
3035 		fprintf(f, " (%s, %s", direction,
3036 			COLOR(root) == RED ? "RED" : "BLACK");
3037 
3038 		if ((! IS_ROOT(root) && PARENT(root) != parent) ||
3039 		    (  IS_ROOT(root) && depth > 0 &&
3040 		       DOWN(PARENT(root)) != root)) {
3041 
3042 			fprintf(f, " (BAD parent pointer! -> ");
3043 			if (PARENT(root) != NULL)
3044 				printnodename(PARENT(root), true, f);
3045 			else
3046 				fprintf(f, "NULL");
3047 			fprintf(f, ")");
3048 		}
3049 
3050 		fprintf(f, ")");
3051 
3052 		if (root->data != NULL && data_printer != NULL) {
3053 			fprintf(f, " data@%p: ", root->data);
3054 			data_printer(f, root->data);
3055 		}
3056 		fprintf(f, "\n");
3057 
3058 		depth++;
3059 
3060 		/*
3061 		 * Don't use IS_RED(root) as it tests for 'root != NULL'
3062 		 * and cppcheck produces false positives.
3063 		 */
3064 		if (COLOR(root) == RED && IS_RED(LEFT(root))) {
3065 			fprintf(f, "** Red/Red color violation on left\n");
3066 		}
3067 		print_text_helper(LEFT(root), root, depth, "left",
3068 					  data_printer, f);
3069 
3070 		/*
3071 		 * Don't use IS_RED(root) as cppcheck produces false positives.
3072 		 */
3073 		if (COLOR(root) == RED && IS_RED(RIGHT(root))) {
3074 			fprintf(f, "** Red/Red color violation on right\n");
3075 		}
3076 		print_text_helper(RIGHT(root), root, depth, "right",
3077 					  data_printer, f);
3078 
3079 		print_text_helper(DOWN(root), NULL, depth, "down",
3080 					  data_printer, f);
3081 	} else {
3082 		fprintf(f, "NULL (%s)\n", direction);
3083 	}
3084 }
3085 
3086 void
3087 dns_rbt_printtext(dns_rbt_t *rbt,
3088 		  void (*data_printer)(FILE *, void *), FILE *f)
3089 {
3090 	REQUIRE(VALID_RBT(rbt));
3091 
3092 	print_text_helper(rbt->root, NULL, 0, "root", data_printer, f);
3093 }
3094 
3095 static int
3096 print_dot_helper(dns_rbtnode_t *node, unsigned int *nodecount,
3097 		 bool show_pointers, FILE *f)
3098 {
3099 	unsigned int l, r, d;
3100 
3101 	if (node == NULL)
3102 		return (0);
3103 
3104 	l = print_dot_helper(LEFT(node), nodecount, show_pointers, f);
3105 	r = print_dot_helper(RIGHT(node), nodecount, show_pointers, f);
3106 	d = print_dot_helper(DOWN(node), nodecount, show_pointers, f);
3107 
3108 	*nodecount += 1;
3109 
3110 	fprintf(f, "node%u[label = \"<f0> |<f1> ", *nodecount);
3111 	printnodename(node, false, f);
3112 	fprintf(f, "|<f2>");
3113 
3114 	if (show_pointers)
3115 		fprintf(f, "|<f3> n=%p|<f4> p=%p", node, PARENT(node));
3116 
3117 	fprintf(f, "\"] [");
3118 
3119 	if (IS_RED(node))
3120 		fprintf(f, "color=red");
3121 	else
3122 		fprintf(f, "color=black");
3123 
3124 	/* XXXMUKS: verify that IS_ROOT() indicates subtree root and not
3125 	 * forest root.
3126 	 */
3127 	if (IS_ROOT(node))
3128 		fprintf(f, ",penwidth=3");
3129 
3130 	if (IS_EMPTY(node))
3131 		fprintf(f, ",style=filled,fillcolor=lightgrey");
3132 
3133 	fprintf(f, "];\n");
3134 
3135 	if (LEFT(node) != NULL)
3136 		fprintf(f, "\"node%u\":f0 -> \"node%u\":f1;\n", *nodecount, l);
3137 
3138 	if (DOWN(node) != NULL)
3139 		fprintf(f, "\"node%u\":f1 -> \"node%u\":f1 [penwidth=5];\n",
3140 			*nodecount, d);
3141 
3142 	if (RIGHT(node) != NULL)
3143 		fprintf(f, "\"node%u\":f2 -> \"node%u\":f1;\n", *nodecount, r);
3144 
3145 	return (*nodecount);
3146 }
3147 
3148 void
3149 dns_rbt_printdot(dns_rbt_t *rbt, bool show_pointers, FILE *f) {
3150 	unsigned int nodecount = 0;
3151 
3152 	REQUIRE(VALID_RBT(rbt));
3153 
3154 	fprintf(f, "digraph g {\n");
3155 	fprintf(f, "node [shape = record,height=.1];\n");
3156 	print_dot_helper(rbt->root, &nodecount, show_pointers, f);
3157 	fprintf(f, "}\n");
3158 }
3159 
3160 /*
3161  * Chain Functions
3162  */
3163 
3164 void
3165 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
3166 
3167 	REQUIRE(chain != NULL);
3168 
3169 	/*
3170 	 * Initialize 'chain'.
3171 	 */
3172 	chain->mctx = mctx;
3173 	chain->end = NULL;
3174 	chain->level_count = 0;
3175 	chain->level_matches = 0;
3176 	memset(chain->levels, 0, sizeof(chain->levels));
3177 
3178 	chain->magic = CHAIN_MAGIC;
3179 }
3180 
3181 isc_result_t
3182 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
3183 			 dns_name_t *origin, dns_rbtnode_t **node)
3184 {
3185 	isc_result_t result = ISC_R_SUCCESS;
3186 
3187 	REQUIRE(VALID_CHAIN(chain));
3188 
3189 	if (node != NULL)
3190 		*node = chain->end;
3191 
3192 	if (chain->end == NULL)
3193 		return (ISC_R_NOTFOUND);
3194 
3195 	if (name != NULL) {
3196 		NODENAME(chain->end, name);
3197 
3198 		if (chain->level_count == 0) {
3199 			/*
3200 			 * Names in the top level tree are all absolute.
3201 			 * Always make 'name' relative.
3202 			 */
3203 			INSIST(dns_name_isabsolute(name));
3204 
3205 			/*
3206 			 * This is cheaper than dns_name_getlabelsequence().
3207 			 */
3208 			name->labels--;
3209 			name->length--;
3210 			name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
3211 		}
3212 	}
3213 
3214 	if (origin != NULL) {
3215 		if (chain->level_count > 0) {
3216 			result = chain_name(chain, origin, false);
3217 		} else {
3218 			dns_name_copynf(dns_rootname, origin);
3219 		}
3220 	}
3221 
3222 	return (result);
3223 }
3224 
3225 isc_result_t
3226 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
3227 		      dns_name_t *origin)
3228 {
3229 	dns_rbtnode_t *current, *previous, *predecessor;
3230 	isc_result_t result = ISC_R_SUCCESS;
3231 	bool new_origin = false;
3232 
3233 	REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
3234 
3235 	predecessor = NULL;
3236 
3237 	current = chain->end;
3238 
3239 	if (LEFT(current) != NULL) {
3240 		/*
3241 		 * Moving left one then right as far as possible is the
3242 		 * previous node, at least for this level.
3243 		 */
3244 		current = LEFT(current);
3245 
3246 		while (RIGHT(current) != NULL)
3247 			current = RIGHT(current);
3248 
3249 		predecessor = current;
3250 
3251 	} else {
3252 		/*
3253 		 * No left links, so move toward the root.  If at any point on
3254 		 * the way there the link from parent to child is a right
3255 		 * link, then the parent is the previous node, at least
3256 		 * for this level.
3257 		 */
3258 		while (! IS_ROOT(current)) {
3259 			previous = current;
3260 			current = PARENT(current);
3261 
3262 			if (RIGHT(current) == previous) {
3263 				predecessor = current;
3264 				break;
3265 			}
3266 		}
3267 	}
3268 
3269 	if (predecessor != NULL) {
3270 		/*
3271 		 * Found a predecessor node in this level.  It might not
3272 		 * really be the predecessor, however.
3273 		 */
3274 		if (DOWN(predecessor) != NULL) {
3275 			/*
3276 			 * The predecessor is really down at least one level.
3277 			 * Go down and as far right as possible, and repeat
3278 			 * as long as the rightmost node has a down pointer.
3279 			 */
3280 			do {
3281 				/*
3282 				 * XXX DCL Need to do something about origins
3283 				 * here. See whether to go down, and if so
3284 				 * whether it is truly what Bob calls a
3285 				 * new origin.
3286 				 */
3287 				ADD_LEVEL(chain, predecessor);
3288 				predecessor = DOWN(predecessor);
3289 
3290 				/* XXX DCL duplicated from above; clever
3291 				 * way to unduplicate? */
3292 
3293 				while (RIGHT(predecessor) != NULL)
3294 					predecessor = RIGHT(predecessor);
3295 			} while (DOWN(predecessor) != NULL);
3296 
3297 			/* XXX DCL probably needs work on the concept */
3298 			if (origin != NULL)
3299 				new_origin = true;
3300 		}
3301 
3302 	} else if (chain->level_count > 0) {
3303 		/*
3304 		 * Dang, didn't find a predecessor in this level.
3305 		 * Got to the root of this level without having traversed
3306 		 * any right links.  Ascend the tree one level; the
3307 		 * node that points to this tree is the predecessor.
3308 		 */
3309 		INSIST(chain->level_count > 0 && IS_ROOT(current));
3310 		predecessor = chain->levels[--chain->level_count];
3311 
3312 		/* XXX DCL probably needs work on the concept */
3313 		/*
3314 		 * Don't declare an origin change when the new origin is "."
3315 		 * at the top level tree, because "." is declared as the origin
3316 		 * for the second level tree.
3317 		 */
3318 		if (origin != NULL &&
3319 		    (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
3320 			new_origin = true;
3321 	}
3322 
3323 	if (predecessor != NULL) {
3324 		chain->end = predecessor;
3325 
3326 		if (new_origin) {
3327 			result = dns_rbtnodechain_current(chain, name, origin,
3328 							  NULL);
3329 			if (result == ISC_R_SUCCESS)
3330 				result = DNS_R_NEWORIGIN;
3331 
3332 		} else
3333 			result = dns_rbtnodechain_current(chain, name, NULL,
3334 							  NULL);
3335 
3336 	} else
3337 		result = ISC_R_NOMORE;
3338 
3339 	return (result);
3340 }
3341 
3342 isc_result_t
3343 dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
3344 		      dns_name_t *origin)
3345 {
3346 	dns_rbtnode_t *current, *successor;
3347 	isc_result_t result = ISC_R_SUCCESS;
3348 	bool new_origin = false;
3349 
3350 	REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
3351 
3352 	successor = NULL;
3353 
3354 	current = chain->end;
3355 
3356 	if (DOWN(current) != NULL) {
3357 		/*
3358 		 * Don't declare an origin change when the new origin is "."
3359 		 * at the second level tree, because "." is already declared
3360 		 * as the origin for the top level tree.
3361 		 */
3362 		if (chain->level_count > 0 ||
3363 		    OFFSETLEN(current) > 1)
3364 			new_origin = true;
3365 
3366 		ADD_LEVEL(chain, current);
3367 		current = DOWN(current);
3368 
3369 		while (LEFT(current) != NULL)
3370 			current = LEFT(current);
3371 
3372 		successor = current;
3373 	}
3374 
3375 	if (successor != NULL) {
3376 		chain->end = successor;
3377 
3378 		/*
3379 		 * It is not necessary to use dns_rbtnodechain_current like
3380 		 * the other functions because this function will never
3381 		 * find a node in the topmost level.  This is because the
3382 		 * root level will never be more than one name, and everything
3383 		 * in the megatree is a successor to that node, down at
3384 		 * the second level or below.
3385 		 */
3386 
3387 		if (name != NULL)
3388 			NODENAME(chain->end, name);
3389 
3390 		if (new_origin) {
3391 			if (origin != NULL)
3392 				result = chain_name(chain, origin, false);
3393 
3394 			if (result == ISC_R_SUCCESS)
3395 				result = DNS_R_NEWORIGIN;
3396 
3397 		} else
3398 			result = ISC_R_SUCCESS;
3399 
3400 	} else
3401 		result = ISC_R_NOMORE;
3402 
3403 	return (result);
3404 }
3405 
3406 isc_result_t
3407 dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) {
3408 	dns_rbtnode_t *current, *previous, *successor;
3409 	isc_result_t result = ISC_R_SUCCESS;
3410 
3411 	REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
3412 
3413 	successor = NULL;
3414 
3415 	current = chain->end;
3416 
3417 	if (RIGHT(current) == NULL) {
3418 		while (! IS_ROOT(current)) {
3419 			previous = current;
3420 			current = PARENT(current);
3421 
3422 			if (LEFT(current) == previous) {
3423 				successor = current;
3424 				break;
3425 			}
3426 		}
3427 	} else {
3428 		current = RIGHT(current);
3429 
3430 		while (LEFT(current) != NULL)
3431 			current = LEFT(current);
3432 
3433 		successor = current;
3434 	}
3435 
3436 	if (successor != NULL) {
3437 		chain->end = successor;
3438 
3439 		if (name != NULL)
3440 			NODENAME(chain->end, name);
3441 
3442 		result = ISC_R_SUCCESS;
3443 	} else
3444 		result = ISC_R_NOMORE;
3445 
3446 	return (result);
3447 }
3448 
3449 isc_result_t
3450 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
3451 		      dns_name_t *origin)
3452 {
3453 	dns_rbtnode_t *current, *previous, *successor;
3454 	isc_result_t result = ISC_R_SUCCESS;
3455 	bool new_origin = false;
3456 
3457 	REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
3458 
3459 	successor = NULL;
3460 
3461 	current = chain->end;
3462 
3463 	/*
3464 	 * If there is a level below this node, the next node is the leftmost
3465 	 * node of the next level.
3466 	 */
3467 	if (DOWN(current) != NULL) {
3468 		/*
3469 		 * Don't declare an origin change when the new origin is "."
3470 		 * at the second level tree, because "." is already declared
3471 		 * as the origin for the top level tree.
3472 		 */
3473 		if (chain->level_count > 0 ||
3474 		    OFFSETLEN(current) > 1)
3475 			new_origin = true;
3476 
3477 		ADD_LEVEL(chain, current);
3478 		current = DOWN(current);
3479 
3480 		while (LEFT(current) != NULL)
3481 			current = LEFT(current);
3482 
3483 		successor = current;
3484 
3485 	} else if (RIGHT(current) == NULL) {
3486 		/*
3487 		 * The successor is up, either in this level or a previous one.
3488 		 * Head back toward the root of the tree, looking for any path
3489 		 * that was via a left link; the successor is the node that has
3490 		 * that left link.  In the event the root of the level is
3491 		 * reached without having traversed any left links, ascend one
3492 		 * level and look for either a right link off the point of
3493 		 * ascent, or search for a left link upward again, repeating
3494 		 * ascends until either case is true.
3495 		 */
3496 		do {
3497 			while (! IS_ROOT(current)) {
3498 				previous = current;
3499 				current = PARENT(current);
3500 
3501 				if (LEFT(current) == previous) {
3502 					successor = current;
3503 					break;
3504 				}
3505 			}
3506 
3507 			if (successor == NULL) {
3508 				/*
3509 				 * Reached the root without having traversed
3510 				 * any left pointers, so this level is done.
3511 				 */
3512 				if (chain->level_count == 0) {
3513 					/*
3514 					 * If the tree we are iterating over
3515 					 * was modified since this chain was
3516 					 * initialized in a way that caused
3517 					 * node splits to occur, "current" may
3518 					 * now be pointing to a root node which
3519 					 * appears to be at level 0, but still
3520 					 * has a parent.  If that happens,
3521 					 * abort.  Otherwise, we are done
3522 					 * looking for a successor as we really
3523 					 * reached the root node on level 0.
3524 					 */
3525 					INSIST(PARENT(current) == NULL);
3526 					break;
3527 				}
3528 
3529 				current = chain->levels[--chain->level_count];
3530 				new_origin = true;
3531 
3532 				if (RIGHT(current) != NULL)
3533 					break;
3534 			}
3535 		} while (successor == NULL);
3536 	}
3537 
3538 	if (successor == NULL && RIGHT(current) != NULL) {
3539 		current = RIGHT(current);
3540 
3541 		while (LEFT(current) != NULL)
3542 			current = LEFT(current);
3543 
3544 		successor = current;
3545 	}
3546 
3547 	if (successor != NULL) {
3548 		/*
3549 		 * If we determine that the current node is the successor to
3550 		 * itself, we will run into an infinite loop, so abort instead.
3551 		 */
3552 		INSIST(chain->end != successor);
3553 
3554 		chain->end = successor;
3555 
3556 		/*
3557 		 * It is not necessary to use dns_rbtnodechain_current like
3558 		 * the other functions because this function will never
3559 		 * find a node in the topmost level.  This is because the
3560 		 * root level will never be more than one name, and everything
3561 		 * in the megatree is a successor to that node, down at
3562 		 * the second level or below.
3563 		 */
3564 
3565 		if (name != NULL)
3566 			NODENAME(chain->end, name);
3567 
3568 		if (new_origin) {
3569 			if (origin != NULL)
3570 				result = chain_name(chain, origin, false);
3571 
3572 			if (result == ISC_R_SUCCESS)
3573 				result = DNS_R_NEWORIGIN;
3574 
3575 		} else
3576 			result = ISC_R_SUCCESS;
3577 
3578 	} else
3579 		result = ISC_R_NOMORE;
3580 
3581 	return (result);
3582 }
3583 
3584 isc_result_t
3585 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
3586 		       dns_name_t *name, dns_name_t *origin)
3587 
3588 {
3589 	isc_result_t result;
3590 
3591 	REQUIRE(VALID_RBT(rbt));
3592 	REQUIRE(VALID_CHAIN(chain));
3593 
3594 	dns_rbtnodechain_reset(chain);
3595 
3596 	chain->end = rbt->root;
3597 
3598 	result = dns_rbtnodechain_current(chain, name, origin, NULL);
3599 
3600 	if (result == ISC_R_SUCCESS)
3601 		result = DNS_R_NEWORIGIN;
3602 
3603 	return (result);
3604 }
3605 
3606 isc_result_t
3607 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
3608 		       dns_name_t *name, dns_name_t *origin)
3609 
3610 {
3611 	isc_result_t result;
3612 
3613 	REQUIRE(VALID_RBT(rbt));
3614 	REQUIRE(VALID_CHAIN(chain));
3615 
3616 	dns_rbtnodechain_reset(chain);
3617 
3618 	result = move_chain_to_last(chain, rbt->root);
3619 	if (result != ISC_R_SUCCESS)
3620 		return (result);
3621 
3622 	result = dns_rbtnodechain_current(chain, name, origin, NULL);
3623 
3624 	if (result == ISC_R_SUCCESS)
3625 		result = DNS_R_NEWORIGIN;
3626 
3627 	return (result);
3628 }
3629 
3630 
3631 void
3632 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
3633 
3634 	REQUIRE(VALID_CHAIN(chain));
3635 
3636 	/*
3637 	 * Free any dynamic storage associated with 'chain', and then
3638 	 * reinitialize 'chain'.
3639 	 */
3640 	chain->end = NULL;
3641 	chain->level_count = 0;
3642 	chain->level_matches = 0;
3643 }
3644 
3645 void
3646 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
3647 	/*
3648 	 * Free any dynamic storage associated with 'chain', and then
3649 	 * invalidate 'chain'.
3650 	 */
3651 
3652 	dns_rbtnodechain_reset(chain);
3653 
3654 	chain->magic = 0;
3655 }
3656 
3657 /* XXXMUKS:
3658  *
3659  * - worth removing inline as static functions are inlined automatically
3660  *   where suitable by modern compilers.
3661  * - bump the size of dns_rbt.nodecount to size_t.
3662  * - the dumpfile header also contains a nodecount that is unsigned
3663  *   int. If large files (> 2^32 nodes) are to be supported, the
3664  *   allocation for this field should be increased.
3665  */
3666