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