rbt.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 /* Principal Authors: DCL */
00021 
00022 #include <config.h>
00023 
00024 #include <sys/stat.h>
00025 #ifdef HAVE_INTTYPES_H
00026 #include <inttypes.h> /* uintptr_t */
00027 #endif
00028 
00029 #include <isc/crc64.h>
00030 #include <isc/file.h>
00031 #include <isc/hex.h>
00032 #include <isc/mem.h>
00033 #include <isc/platform.h>
00034 #include <isc/print.h>
00035 #include <isc/refcount.h>
00036 #include <isc/socket.h>
00037 #include <isc/stdio.h>
00038 #include <isc/string.h>
00039 #include <isc/util.h>
00040 
00041 /*%
00042  * This define is so dns/name.h (included by dns/fixedname.h) uses more
00043  * efficient macro calls instead of functions for a few operations.
00044  */
00045 #define DNS_NAME_USEINLINE 1
00046 
00047 #include <dns/fixedname.h>
00048 #include <dns/log.h>
00049 #include <dns/rbt.h>
00050 #include <dns/result.h>
00051 #include <dns/version.h>
00052 
00053 #include <unistd.h>
00054 
00055 #define CHECK(x) \
00056         do { \
00057                 result = (x); \
00058                 if (result != ISC_R_SUCCESS) \
00059                         goto cleanup; \
00060         } while (0)
00061 
00062 #define RBT_MAGIC               ISC_MAGIC('R', 'B', 'T', '+')
00063 #define VALID_RBT(rbt)          ISC_MAGIC_VALID(rbt, RBT_MAGIC)
00064 
00065 /*
00066  * XXXDCL Since parent pointers were added in again, I could remove all of the
00067  * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
00068  * _lastnode.  This would involve pretty major change to the API.
00069  */
00070 #define CHAIN_MAGIC             ISC_MAGIC('0', '-', '0', '-')
00071 #define VALID_CHAIN(chain)      ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
00072 
00073 #define RBT_HASH_SIZE           64
00074 
00075 #ifdef RBT_MEM_TEST
00076 #undef RBT_HASH_SIZE
00077 #define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
00078 #endif
00079 
00080 struct dns_rbt {
00081         unsigned int            magic;
00082         isc_mem_t *             mctx;
00083         dns_rbtnode_t *         root;
00084         void                    (*data_deleter)(void *, void *);
00085         void *                  deleter_arg;
00086         unsigned int            nodecount;
00087         unsigned int            hashsize;
00088         dns_rbtnode_t **        hashtable;
00089         void *                  mmap_location;
00090 };
00091 
00092 #define RED 0
00093 #define BLACK 1
00094 
00095 /*
00096  * This is the header for map-format RBT images.  It is populated,
00097  * and then written, as the LAST thing done to the file before returning.
00098  * Writing this last (with zeros in the header area initially) will ensure
00099  * that the header is only valid when the RBT image is also valid.
00100  */
00101 typedef struct file_header file_header_t;
00102 
00103 /* Pad to 32 bytes */
00104 static char FILE_VERSION[32] = "\0";
00105 
00106 /* Header length, always the same size regardless of structure size */
00107 #define HEADER_LENGTH           1024
00108 
00109 struct file_header {
00110         char version1[32];
00111         isc_uint64_t first_node_offset; /* usually 1024 */
00112         /*
00113          * information about the system on which the map file was generated
00114          * will be used to tell if we can load the map file or not
00115          */
00116         isc_uint32_t ptrsize;
00117         unsigned int bigendian:1;       /* big or little endian system */
00118         unsigned int rdataset_fixed:1;  /* compiled with --enable-rrset-fixed */
00119         unsigned int nodecount;         /* shadow from rbt structure */
00120         isc_uint64_t crc;
00121         char version2[32];              /* repeated; must match version1 */
00122 };
00123 
00124 /*
00125  * The following declarations are for the serialization of an RBT:
00126  *
00127  * step one: write out a zeroed header of 1024 bytes
00128  * step two: walk the tree in a depth-first, left-right-down order, writing
00129  * out the nodes, reserving space as we go, correcting addresses to point
00130  * at the proper offset in the file, and setting a flag for each pointer to
00131  * indicate that it is a reference to a location in the file, rather than in
00132  * memory.
00133  * step three: write out the header, adding the information that will be
00134  * needed to re-create the tree object itself.
00135  *
00136  * The RBTDB object will do this three times, once for each of the three
00137  * RBT objects it contains.
00138  *
00139  * Note: 'file' must point an actual open file that can be mmapped
00140  * and fseeked, not to a pipe or stream
00141  */
00142 
00143 static isc_result_t
00144 dns_rbt_zero_header(FILE *file);
00145 
00146 static isc_result_t
00147 write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
00148              isc_uint64_t crc);
00149 
00150 static isc_result_t
00151 serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
00152                uintptr_t right, uintptr_t down, uintptr_t parent,
00153                uintptr_t data, isc_uint64_t *crc);
00154 
00155 static isc_result_t
00156 serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
00157                 dns_rbtdatawriter_t datawriter, void *writer_arg,
00158                 uintptr_t *where, isc_uint64_t *crc);
00159 /*
00160  * The following functions allow you to get the actual address of a pointer
00161  * without having to use an if statement to check to see if that address is
00162  * relative or not
00163  */
00164 static inline dns_rbtnode_t *
00165 getparent(dns_rbtnode_t *node, file_header_t *header) {
00166         char *adjusted_address = (char *)(node->parent);
00167         adjusted_address += node->parent_is_relative * (uintptr_t)header;
00168 
00169         return ((dns_rbtnode_t *)adjusted_address);
00170 }
00171 
00172 static inline dns_rbtnode_t *
00173 getleft(dns_rbtnode_t *node, file_header_t *header) {
00174         char *adjusted_address = (char *)(node->left);
00175         adjusted_address += node->left_is_relative * (uintptr_t)header;
00176 
00177         return ((dns_rbtnode_t *)adjusted_address);
00178 }
00179 
00180 static inline dns_rbtnode_t *
00181 getright(dns_rbtnode_t *node, file_header_t *header) {
00182         char *adjusted_address = (char *)(node->right);
00183         adjusted_address += node->right_is_relative * (uintptr_t)header;
00184 
00185         return ((dns_rbtnode_t *)adjusted_address);
00186 }
00187 
00188 static inline dns_rbtnode_t *
00189 getdown(dns_rbtnode_t *node, file_header_t *header) {
00190         char *adjusted_address = (char *)(node->down);
00191         adjusted_address += node->down_is_relative * (uintptr_t)header;
00192 
00193         return ((dns_rbtnode_t *)adjusted_address);
00194 }
00195 
00196 static inline dns_rbtnode_t *
00197 getdata(dns_rbtnode_t *node, file_header_t *header) {
00198         char *adjusted_address = (char *)(node->data);
00199         adjusted_address += node->data_is_relative * (uintptr_t)header;
00200 
00201         return ((dns_rbtnode_t *)adjusted_address);
00202 }
00203 
00204 /*%
00205  * Elements of the rbtnode structure.
00206  */
00207 #define PARENT(node)            ((node)->parent)
00208 #define LEFT(node)              ((node)->left)
00209 #define RIGHT(node)             ((node)->right)
00210 #define DOWN(node)              ((node)->down)
00211 #define DATA(node)              ((node)->data)
00212 #define IS_EMPTY(node)          ((node)->data == NULL)
00213 #define HASHNEXT(node)          ((node)->hashnext)
00214 #define HASHVAL(node)           ((node)->hashval)
00215 #define COLOR(node)             ((node)->color)
00216 #define NAMELEN(node)           ((node)->namelen)
00217 #define OLDNAMELEN(node)        ((node)->oldnamelen)
00218 #define OFFSETLEN(node)         ((node)->offsetlen)
00219 #define ATTRS(node)             ((node)->attributes)
00220 #define IS_ROOT(node)           ISC_TF((node)->is_root == 1)
00221 #define FINDCALLBACK(node)      ISC_TF((node)->find_callback == 1)
00222 
00223 /*%
00224  * Structure elements from the rbtdb.c, not
00225  * used as part of the rbt.c algorithms.
00226  */
00227 #define DIRTY(node)     ((node)->dirty)
00228 #define WILD(node)      ((node)->wild)
00229 #define LOCKNUM(node)   ((node)->locknum)
00230 
00231 /*%
00232  * The variable length stuff stored after the node has the following
00233  * structure.
00234  *
00235  *      <name_data>{1..255}<oldoffsetlen>{1}<offsets>{1..128}
00236  *
00237  * <name_data> contains the name of the node when it was created.
00238  * <oldoffsetlen> contains the length of <offsets> when the node was created.
00239  * <offsets> contains the offets into name for each label when the node was
00240  * created.
00241  */
00242 
00243 #define NAME(node)      ((unsigned char *)((node) + 1))
00244 #define OFFSETS(node)   (NAME(node) + OLDNAMELEN(node) + 1)
00245 #define OLDOFFSETLEN(node) (OFFSETS(node)[-1])
00246 
00247 #define NODE_SIZE(node) (sizeof(*node) + \
00248                          OLDNAMELEN(node) + OLDOFFSETLEN(node) + 1)
00249 
00250 /*%
00251  * Color management.
00252  */
00253 #define IS_RED(node)            ((node) != NULL && (node)->color == RED)
00254 #define IS_BLACK(node)          ((node) == NULL || (node)->color == BLACK)
00255 #define MAKE_RED(node)          ((node)->color = RED)
00256 #define MAKE_BLACK(node)        ((node)->color = BLACK)
00257 
00258 /*%
00259  * Chain management.
00260  *
00261  * The "ancestors" member of chains were removed, with their job now
00262  * being wholly handled by parent pointers (which didn't exist, because
00263  * of memory concerns, when chains were first implemented).
00264  */
00265 #define ADD_LEVEL(chain, node) \
00266         do { \
00267                 INSIST((chain)->level_count < DNS_RBT_LEVELBLOCK); \
00268                 (chain)->levels[(chain)->level_count++] = (node); \
00269         } while (0)
00270 
00271 /*%
00272  * The following macros directly access normally private name variables.
00273  * These macros are used to avoid a lot of function calls in the critical
00274  * path of the tree traversal code.
00275  */
00276 
00277 static inline void
00278 NODENAME(dns_rbtnode_t *node, dns_name_t *name) {
00279         name->length = NAMELEN(node);
00280         name->labels = OFFSETLEN(node);
00281         name->ndata = NAME(node);
00282         name->offsets = OFFSETS(node);
00283         name->attributes = ATTRS(node);
00284         name->attributes |= DNS_NAMEATTR_READONLY;
00285 }
00286 
00287 void
00288 dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name) {
00289         name->length = NAMELEN(node);
00290         name->labels = OFFSETLEN(node);
00291         name->ndata = NAME(node);
00292         name->offsets = OFFSETS(node);
00293         name->attributes = ATTRS(node);
00294         name->attributes |= DNS_NAMEATTR_READONLY;
00295 }
00296 
00297 dns_rbtnode_t *
00298 dns_rbt_root(dns_rbt_t *rbt) {
00299   return rbt->root;
00300 }
00301 
00302 #ifdef DNS_RBT_USEHASH
00303 static isc_result_t
00304 inithash(dns_rbt_t *rbt);
00305 #endif
00306 
00307 #ifdef DEBUG
00308 #define inline
00309 /*
00310  * A little something to help out in GDB.
00311  */
00312 dns_name_t Name(dns_rbtnode_t *node);
00313 dns_name_t
00314 Name(dns_rbtnode_t *node) {
00315         dns_name_t name;
00316 
00317         dns_name_init(&name, NULL);
00318         if (node != NULL)
00319                 NODENAME(node, &name);
00320 
00321         return (name);
00322 }
00323 
00324 static void
00325 hexdump(const char *desc, unsigned char *data, size_t size) {
00326         char hexdump[BUFSIZ * 2 + 1];
00327         isc_buffer_t b;
00328         isc_region_t r;
00329         isc_result_t result;
00330         size_t bytes;
00331 
00332         fprintf(stderr, "%s: ", desc);
00333         do {
00334                 isc_buffer_init(&b, hexdump, sizeof(hexdump));
00335                 r.base = data;
00336                 r.length = bytes = (size > BUFSIZ) ? BUFSIZ : size;
00337                 result = isc_hex_totext(&r, 0, "", &b);
00338                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00339                 isc_buffer_putuint8(&b, 0);
00340                 fprintf(stderr, "%s", hexdump);
00341                 data += bytes;
00342                 size -= bytes;
00343         } while (size > 0);
00344         fprintf(stderr, "\n");
00345 }
00346 #endif /* DEBUG */
00347 
00348 /* The passed node must not be NULL. */
00349 static inline dns_rbtnode_t *
00350 get_subtree_root(dns_rbtnode_t *node) {
00351         while (!IS_ROOT(node)) {
00352                 node = PARENT(node);
00353         }
00354 
00355         return (node);
00356 }
00357 
00358 /* Upper node is the parent of the root of the passed node's
00359  * subtree. The passed node must not be NULL.
00360  */
00361 static inline dns_rbtnode_t *
00362 get_upper_node(dns_rbtnode_t *node) {
00363         dns_rbtnode_t *root = get_subtree_root(node);
00364 
00365         /*
00366          * Return the node in the level above the argument node that points
00367          * to the level the argument node is in.  If the argument node is in
00368          * the top level, the return value is NULL.
00369          */
00370         return (PARENT(root));
00371 }
00372 
00373 size_t
00374 dns__rbtnode_getdistance(dns_rbtnode_t *node) {
00375         size_t nodes = 1;
00376 
00377         while (node != NULL) {
00378                 if (IS_ROOT(node))
00379                         break;
00380                 nodes++;
00381                 node = PARENT(node);
00382         }
00383 
00384         return (nodes);
00385 }
00386 
00387 /*
00388  * Forward declarations.
00389  */
00390 static isc_result_t
00391 create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep);
00392 
00393 #ifdef DNS_RBT_USEHASH
00394 static inline void
00395 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name);
00396 static inline void
00397 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node);
00398 static void
00399 rehash(dns_rbt_t *rbt, unsigned int newcount);
00400 #else
00401 #define hash_node(rbt, node, name)
00402 #define unhash_node(rbt, node)
00403 #define rehash(rbt, newcount)
00404 #endif
00405 
00406 static inline void
00407 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
00408 static inline void
00409 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
00410 
00411 static void
00412 addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
00413            dns_rbtnode_t **rootp);
00414 
00415 static void
00416 deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp);
00417 
00418 static isc_result_t
00419 treefix(dns_rbt_t *rbt, void *base, size_t size,
00420         dns_rbtnode_t *n, dns_name_t *name,
00421         dns_rbtdatafixer_t datafixer, void *fixer_arg,
00422         isc_uint64_t *crc);
00423 
00424 static isc_result_t
00425 deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node);
00426 
00427 static void
00428 deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, dns_rbtnode_t **nodep);
00429 
00430 static void
00431 printnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f);
00432 
00433 static void
00434 freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep);
00435 
00436 static isc_result_t
00437 dns_rbt_zero_header(FILE *file) {
00438         /*
00439          * Write out a zeroed header as a placeholder.  Doing this ensures
00440          * that the file will not read while it is partially written, should
00441          * writing fail or be interrupted.
00442          */
00443         char buffer[HEADER_LENGTH];
00444         isc_result_t result;
00445 
00446         memset(buffer, 0, HEADER_LENGTH);
00447         result = isc_stdio_write(buffer, 1, HEADER_LENGTH, file, NULL);
00448         if (result != ISC_R_SUCCESS)
00449                 return (result);
00450 
00451         result = fflush(file);
00452         if (result != ISC_R_SUCCESS)
00453                 return (result);
00454 
00455         return (ISC_R_SUCCESS);
00456 }
00457 
00458 /*
00459  * Write out the real header, including NodeDump version information
00460  * and the offset of the first node.
00461  *
00462  * Any information stored in the rbt object itself should be stored
00463  * here.
00464  */
00465 static isc_result_t
00466 write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
00467              isc_uint64_t crc)
00468 {
00469         file_header_t header;
00470         isc_result_t result;
00471         off_t location;
00472 
00473         if (FILE_VERSION[0] == '\0') {
00474                 memset(FILE_VERSION, 0, sizeof(FILE_VERSION));
00475                 snprintf(FILE_VERSION, sizeof(FILE_VERSION),
00476                          "RBT Image %s %s", dns_major, dns_mapapi);
00477         }
00478 
00479         memset(&header, 0, sizeof(file_header_t));
00480         memmove(header.version1, FILE_VERSION, sizeof(header.version1));
00481         memmove(header.version2, FILE_VERSION, sizeof(header.version2));
00482         header.first_node_offset = first_node_offset;
00483         header.ptrsize = (isc_uint32_t) sizeof(void *);
00484         header.bigendian = (1 == htonl(1)) ? 1 : 0;
00485 
00486 #ifdef DNS_RDATASET_FIXED
00487         header.rdataset_fixed = 1;
00488 #else
00489         header.rdataset_fixed = 0;
00490 #endif
00491 
00492         header.nodecount = rbt->nodecount;
00493 
00494         header.crc = crc;
00495 
00496         CHECK(isc_stdio_tell(file, &location));
00497         location = dns_rbt_serialize_align(location);
00498         CHECK(isc_stdio_seek(file, location, SEEK_SET));
00499         CHECK(isc_stdio_write(&header, 1, sizeof(file_header_t), file, NULL));
00500         CHECK(fflush(file));
00501 
00502         /* Ensure we are always at the end of the file. */
00503         CHECK(isc_stdio_seek(file, 0, SEEK_END));
00504 
00505  cleanup:
00506         return (result);
00507 }
00508 
00509 static isc_result_t
00510 serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
00511                uintptr_t right, uintptr_t down, uintptr_t parent,
00512                uintptr_t data, isc_uint64_t *crc)
00513 {
00514         dns_rbtnode_t temp_node;
00515         off_t file_position;
00516         unsigned char *node_data;
00517         size_t datasize;
00518         isc_result_t result;
00519 #ifdef DEBUG
00520         dns_name_t nodename;
00521 #endif
00522 
00523         INSIST(node != NULL);
00524 
00525         CHECK(isc_stdio_tell(file, &file_position));
00526         file_position = dns_rbt_serialize_align(file_position);
00527         CHECK(isc_stdio_seek(file, file_position, SEEK_SET));
00528 
00529         temp_node = *node;
00530         temp_node.down_is_relative = 0;
00531         temp_node.left_is_relative = 0;
00532         temp_node.right_is_relative = 0;
00533         temp_node.parent_is_relative = 0;
00534         temp_node.data_is_relative = 0;
00535         temp_node.is_mmapped = 1;
00536 
00537         /*
00538          * If the next node is not NULL, calculate the next node's location
00539          * in the file.  Note that this will have to change when the data
00540          * structure changes, and it also assumes that we always write the
00541          * nodes out in list order (which we currently do.)
00542         */
00543         if (temp_node.parent != NULL) {
00544                 temp_node.parent = (dns_rbtnode_t *)(parent);
00545                 temp_node.parent_is_relative = 1;
00546         }
00547         if (temp_node.left != NULL) {
00548                 temp_node.left = (dns_rbtnode_t *)(left);
00549                 temp_node.left_is_relative = 1;
00550         }
00551         if (temp_node.right != NULL) {
00552                 temp_node.right = (dns_rbtnode_t *)(right);
00553                 temp_node.right_is_relative = 1;
00554         }
00555         if (temp_node.down != NULL) {
00556                 temp_node.down = (dns_rbtnode_t *)(down);
00557                 temp_node.down_is_relative = 1;
00558         }
00559         if (temp_node.data != NULL) {
00560                 temp_node.data = (dns_rbtnode_t *)(data);
00561                 temp_node.data_is_relative = 1;
00562         }
00563 
00564         node_data = (unsigned char *) node + sizeof(dns_rbtnode_t);
00565         datasize = NODE_SIZE(node) - sizeof(dns_rbtnode_t);
00566 
00567         CHECK(isc_stdio_write(&temp_node, 1, sizeof(dns_rbtnode_t),
00568                               file, NULL));
00569         CHECK(isc_stdio_write(node_data, 1, datasize, file, NULL));
00570 
00571 #ifdef DEBUG
00572         dns_name_init(&nodename, NULL);
00573         NODENAME(node, &nodename);
00574         fprintf(stderr, "serialize ");
00575         dns_name_print(&nodename, stderr);
00576         fprintf(stderr, "\n");
00577         hexdump("node header", (unsigned char*) &temp_node,
00578                 sizeof(dns_rbtnode_t));
00579         hexdump("node data", node_data, datasize);
00580 #endif
00581 
00582         isc_crc64_update(crc, (const isc_uint8_t *) &temp_node,
00583                         sizeof(dns_rbtnode_t));
00584         isc_crc64_update(crc, (const isc_uint8_t *) node_data, datasize);
00585 
00586  cleanup:
00587         return (result);
00588 }
00589 
00590 static isc_result_t
00591 serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
00592                 dns_rbtdatawriter_t datawriter, void *writer_arg,
00593                 uintptr_t *where, isc_uint64_t *crc)
00594 {
00595         uintptr_t left = 0, right = 0, down = 0, data = 0;
00596         off_t location = 0, offset_adjust;
00597         isc_result_t result;
00598 
00599         if (node == NULL) {
00600                 if (where != NULL)
00601                         *where = 0;
00602                 return (ISC_R_SUCCESS);
00603         }
00604 
00605         /* Reserve space for current node. */
00606         CHECK(isc_stdio_tell(file, &location));
00607         location = dns_rbt_serialize_align(location);
00608         CHECK(isc_stdio_seek(file, location, SEEK_SET));
00609 
00610         offset_adjust = dns_rbt_serialize_align(location + NODE_SIZE(node));
00611         CHECK(isc_stdio_seek(file, offset_adjust, SEEK_SET));
00612 
00613         /*
00614          * Serialize the rest of the tree.
00615          *
00616          * WARNING: A change in the order (from left, right, down)
00617          * will break the way the crc hash is computed.
00618          */
00619         CHECK(serialize_nodes(file, getleft(node, NULL), location,
00620                               datawriter, writer_arg, &left, crc));
00621         CHECK(serialize_nodes(file, getright(node, NULL), location,
00622                               datawriter, writer_arg, &right, crc));
00623         CHECK(serialize_nodes(file, getdown(node, NULL), location,
00624                               datawriter, writer_arg, &down, crc));
00625 
00626         if (node->data != NULL) {
00627                 off_t ret;
00628 
00629                 CHECK(isc_stdio_tell(file, &ret));
00630                 ret = dns_rbt_serialize_align(ret);
00631                 CHECK(isc_stdio_seek(file, ret, SEEK_SET));
00632                 data = ret;
00633 
00634                 datawriter(file, node->data, writer_arg, crc);
00635         }
00636 
00637         /* Seek back to reserved space. */
00638         CHECK(isc_stdio_seek(file, location, SEEK_SET));
00639 
00640         /* Serialize the current node. */
00641         CHECK(serialize_node(file, node, left, right, down, parent, data, crc));
00642 
00643         /* Ensure we are always at the end of the file. */
00644         CHECK(isc_stdio_seek(file, 0, SEEK_END));
00645 
00646         if (where != NULL)
00647                 *where = (uintptr_t) location;
00648 
00649  cleanup:
00650         return (result);
00651 }
00652 
00653 off_t
00654 dns_rbt_serialize_align(off_t target) {
00655         off_t offset = target % 8;
00656 
00657         if (offset == 0)
00658                 return (target);
00659         else
00660                 return (target + 8 - offset);
00661 }
00662 
00663 isc_result_t
00664 dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt,
00665                        dns_rbtdatawriter_t datawriter,
00666                        void *writer_arg, off_t *offset)
00667 {
00668         isc_result_t result;
00669         off_t header_position, node_position, end_position;
00670         isc_uint64_t crc;
00671 
00672         REQUIRE(file != NULL);
00673 
00674         CHECK(isc_file_isplainfilefd(fileno(file)));
00675 
00676         isc_crc64_init(&crc);
00677 
00678         CHECK(isc_stdio_tell(file, &header_position));
00679 
00680         /* Write dummy header */
00681         CHECK(dns_rbt_zero_header(file));
00682 
00683         /* Serialize nodes */
00684         CHECK(isc_stdio_tell(file, &node_position));
00685         CHECK(serialize_nodes(file, rbt->root, 0, datawriter,
00686                               writer_arg, NULL, &crc));
00687 
00688         CHECK(isc_stdio_tell(file, &end_position));
00689         if (node_position == end_position) {
00690                 CHECK(isc_stdio_seek(file, header_position, SEEK_SET));
00691                 *offset = 0;
00692                 return (ISC_R_SUCCESS);
00693         }
00694 
00695         isc_crc64_final(&crc);
00696 #ifdef DEBUG
00697         hexdump("serializing CRC", (unsigned char *)&crc, sizeof(crc));
00698 #endif
00699 
00700         /* Serialize header */
00701         CHECK(isc_stdio_seek(file, header_position, SEEK_SET));
00702         CHECK(write_header(file, rbt, HEADER_LENGTH, crc));
00703 
00704         /* Ensure we are always at the end of the file. */
00705         CHECK(isc_stdio_seek(file, 0, SEEK_END));
00706         *offset = dns_rbt_serialize_align(header_position);
00707 
00708  cleanup:
00709         return (result);
00710 }
00711 
00712 #define CONFIRM(a) do { \
00713         if (! (a)) { \
00714                 result = ISC_R_INVALIDFILE; \
00715                 goto cleanup; \
00716         } \
00717 } while(0);
00718 
00719 static isc_result_t
00720 treefix(dns_rbt_t *rbt, void *base, size_t filesize, dns_rbtnode_t *n,
00721         dns_name_t *name, dns_rbtdatafixer_t datafixer,
00722         void *fixer_arg, isc_uint64_t *crc)
00723 {
00724         isc_result_t result = ISC_R_SUCCESS;
00725         dns_fixedname_t fixed;
00726         dns_name_t nodename, *fullname;
00727         unsigned char *node_data;
00728         dns_rbtnode_t header;
00729         size_t datasize, nodemax = filesize - sizeof(dns_rbtnode_t);
00730 
00731         if (n == NULL)
00732                 return (ISC_R_SUCCESS);
00733 
00734         CONFIRM((void *) n >= base);
00735         CONFIRM((char *) n - (char *) base <= (int) nodemax);
00736         CONFIRM(DNS_RBTNODE_VALID(n));
00737 
00738         dns_name_init(&nodename, NULL);
00739         NODENAME(n, &nodename);
00740 
00741         fullname = &nodename;
00742         CONFIRM(dns_name_isvalid(fullname));
00743 
00744         if (!dns_name_isabsolute(&nodename)) {
00745                 dns_fixedname_init(&fixed);
00746                 fullname = dns_fixedname_name(&fixed);
00747                 CHECK(dns_name_concatenate(&nodename, name, fullname, NULL));
00748         }
00749 
00750         /* memorize header contents prior to fixup */
00751         memmove(&header, n, sizeof(header));
00752 
00753         if (n->left_is_relative) {
00754                 CONFIRM(n->left <= (dns_rbtnode_t *) nodemax);
00755                 n->left = getleft(n, rbt->mmap_location);
00756                 n->left_is_relative = 0;
00757                 CONFIRM(DNS_RBTNODE_VALID(n->left));
00758         } else
00759                 CONFIRM(n->left == NULL);
00760 
00761         if (n->right_is_relative) {
00762                 CONFIRM(n->right <= (dns_rbtnode_t *) nodemax);
00763                 n->right = getright(n, rbt->mmap_location);
00764                 n->right_is_relative = 0;
00765                 CONFIRM(DNS_RBTNODE_VALID(n->right));
00766         } else
00767                 CONFIRM(n->right == NULL);
00768 
00769         if (n->down_is_relative) {
00770                 CONFIRM(n->down <= (dns_rbtnode_t *) nodemax);
00771                 n->down = getdown(n, rbt->mmap_location);
00772                 n->down_is_relative = 0;
00773                 CONFIRM(n->down > (dns_rbtnode_t *) n);
00774                 CONFIRM(DNS_RBTNODE_VALID(n->down));
00775         } else
00776                 CONFIRM(n->down == NULL);
00777 
00778         if (n->parent_is_relative) {
00779                 CONFIRM(n->parent <= (dns_rbtnode_t *) nodemax);
00780                 n->parent = getparent(n, rbt->mmap_location);
00781                 n->parent_is_relative = 0;
00782                 CONFIRM(n->parent < (dns_rbtnode_t *) n);
00783                 CONFIRM(DNS_RBTNODE_VALID(n->parent));
00784         } else
00785                 CONFIRM(n->parent == NULL);
00786 
00787         if (n->data_is_relative) {
00788                 CONFIRM(n->data <= (void *) filesize);
00789                 n->data = getdata(n, rbt->mmap_location);
00790                 n->data_is_relative = 0;
00791                 CONFIRM(n->data > (void *) n);
00792         } else
00793                 CONFIRM(n->data == NULL);
00794 
00795         hash_node(rbt, n, fullname);
00796 
00797         /* a change in the order (from left, right, down) will break hashing*/
00798         if (n->left != NULL)
00799                 CHECK(treefix(rbt, base, filesize, n->left, name,
00800                               datafixer, fixer_arg, crc));
00801         if (n->right != NULL)
00802                 CHECK(treefix(rbt, base, filesize, n->right, name,
00803                               datafixer, fixer_arg, crc));
00804         if (n->down != NULL)
00805                 CHECK(treefix(rbt, base, filesize, n->down, fullname,
00806                               datafixer, fixer_arg, crc));
00807 
00808         if (datafixer != NULL && n->data != NULL)
00809                 CHECK(datafixer(n, base, filesize, fixer_arg, crc));
00810 
00811         rbt->nodecount++;
00812         node_data = (unsigned char *) n + sizeof(dns_rbtnode_t);
00813         datasize = NODE_SIZE(n) - sizeof(dns_rbtnode_t);
00814 
00815 #ifdef DEBUG
00816         fprintf(stderr, "deserialize ");
00817         dns_name_print(&nodename, stderr);
00818         fprintf(stderr, "\n");
00819         hexdump("node header", (unsigned char *) &header,
00820                 sizeof(dns_rbtnode_t));
00821         hexdump("node data", node_data, datasize);
00822 #endif
00823         isc_crc64_update(crc, (const isc_uint8_t *) &header,
00824                         sizeof(dns_rbtnode_t));
00825         isc_crc64_update(crc, (const isc_uint8_t *) node_data,
00826                         datasize);
00827 
00828  cleanup:
00829         return (result);
00830 }
00831 
00832 isc_result_t
00833 dns_rbt_deserialize_tree(void *base_address, size_t filesize,
00834                          off_t header_offset, isc_mem_t *mctx,
00835                          dns_rbtdeleter_t deleter, void *deleter_arg,
00836                          dns_rbtdatafixer_t datafixer, void *fixer_arg,
00837                          dns_rbtnode_t **originp, dns_rbt_t **rbtp)
00838 {
00839         isc_result_t result = ISC_R_SUCCESS;
00840         file_header_t *header;
00841         dns_rbt_t *rbt = NULL;
00842         isc_uint64_t crc;
00843 
00844         REQUIRE(originp == NULL || *originp == NULL);
00845         REQUIRE(rbtp != NULL && *rbtp == NULL);
00846 
00847         isc_crc64_init(&crc);
00848 
00849         CHECK(dns_rbt_create(mctx, deleter, deleter_arg, &rbt));
00850 
00851         rbt->mmap_location = base_address;
00852 
00853         header = (file_header_t *)((char *)base_address + header_offset);
00854 
00855 #ifdef DNS_RDATASET_FIXED
00856         if (header->rdataset_fixed != 1) {
00857                 result = ISC_R_INVALIDFILE;
00858                 goto cleanup;
00859         }
00860 
00861 #else
00862         if (header->rdataset_fixed != 0) {
00863                 result = ISC_R_INVALIDFILE;
00864                 goto cleanup;
00865         }
00866 #endif
00867 
00868         if (header->ptrsize != (isc_uint32_t) sizeof(void *)) {
00869                 result = ISC_R_INVALIDFILE;
00870                 goto cleanup;
00871         }
00872         if (header->bigendian != (1 == htonl(1)) ? 1 : 0) {
00873                 result = ISC_R_INVALIDFILE;
00874                 goto cleanup;
00875         }
00876 
00877         /* Copy other data items from the header into our rbt. */
00878         rbt->root = (dns_rbtnode_t *)((char *)base_address +
00879                                 header_offset + header->first_node_offset);
00880 
00881         if ((header->nodecount * sizeof(dns_rbtnode_t)) > filesize) {
00882                 result = ISC_R_INVALIDFILE;
00883                 goto cleanup;
00884         }
00885         rehash(rbt, header->nodecount);
00886 
00887         CHECK(treefix(rbt, base_address, filesize, rbt->root,
00888                       dns_rootname, datafixer, fixer_arg, &crc));
00889 
00890         isc_crc64_final(&crc);
00891 #ifdef DEBUG
00892         hexdump("deserializing CRC", (unsigned char *)&crc, sizeof(crc));
00893 #endif
00894 
00895         /* Check file hash */
00896         if (header->crc != crc) {
00897                 result = ISC_R_INVALIDFILE;
00898                 goto cleanup;
00899         }
00900 
00901         *rbtp = rbt;
00902         if (originp != NULL)
00903                 *originp = rbt->root;
00904 
00905         if (header->nodecount != rbt->nodecount)
00906                 result = ISC_R_INVALIDFILE;
00907 
00908  cleanup:
00909         if (result != ISC_R_SUCCESS && rbt != NULL) {
00910                 rbt->root = NULL;
00911                 rbt->nodecount = 0;
00912                 dns_rbt_destroy(&rbt);
00913         }
00914 
00915         return (result);
00916 }
00917 
00918 /*
00919  * Initialize a red/black tree of trees.
00920  */
00921 isc_result_t
00922 dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter,
00923                void *deleter_arg, dns_rbt_t **rbtp)
00924 {
00925 #ifdef DNS_RBT_USEHASH
00926         isc_result_t result;
00927 #endif
00928         dns_rbt_t *rbt;
00929 
00930         REQUIRE(mctx != NULL);
00931         REQUIRE(rbtp != NULL && *rbtp == NULL);
00932         REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
00933 
00934         rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
00935         if (rbt == NULL)
00936                 return (ISC_R_NOMEMORY);
00937 
00938         rbt->mctx = NULL;
00939         isc_mem_attach(mctx, &rbt->mctx);
00940         rbt->data_deleter = deleter;
00941         rbt->deleter_arg = deleter_arg;
00942         rbt->root = NULL;
00943         rbt->nodecount = 0;
00944         rbt->hashtable = NULL;
00945         rbt->hashsize = 0;
00946         rbt->mmap_location = NULL;
00947 
00948 #ifdef DNS_RBT_USEHASH
00949         result = inithash(rbt);
00950         if (result != ISC_R_SUCCESS) {
00951                 isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
00952                 return (result);
00953         }
00954 #endif
00955 
00956         rbt->magic = RBT_MAGIC;
00957 
00958         *rbtp = rbt;
00959 
00960         return (ISC_R_SUCCESS);
00961 }
00962 
00963 /*
00964  * Deallocate a red/black tree of trees.
00965  */
00966 void
00967 dns_rbt_destroy(dns_rbt_t **rbtp) {
00968         RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
00969 }
00970 
00971 isc_result_t
00972 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
00973         dns_rbt_t *rbt;
00974 
00975         REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
00976 
00977         rbt = *rbtp;
00978 
00979         deletetreeflat(rbt, quantum, &rbt->root);
00980         if (rbt->root != NULL)
00981                 return (ISC_R_QUOTA);
00982 
00983         INSIST(rbt->nodecount == 0);
00984 
00985         rbt->mmap_location = NULL;
00986 
00987         if (rbt->hashtable != NULL)
00988                 isc_mem_put(rbt->mctx, rbt->hashtable,
00989                             rbt->hashsize * sizeof(dns_rbtnode_t *));
00990 
00991         rbt->magic = 0;
00992 
00993         isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
00994         *rbtp = NULL;
00995         return (ISC_R_SUCCESS);
00996 }
00997 
00998 unsigned int
00999 dns_rbt_nodecount(dns_rbt_t *rbt) {
01000 
01001         REQUIRE(VALID_RBT(rbt));
01002 
01003         return (rbt->nodecount);
01004 }
01005 
01006 unsigned int
01007 dns_rbt_hashsize(dns_rbt_t *rbt) {
01008 
01009         REQUIRE(VALID_RBT(rbt));
01010 
01011         return (rbt->hashsize);
01012 }
01013 
01014 static inline isc_result_t
01015 chain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
01016            isc_boolean_t include_chain_end)
01017 {
01018         dns_name_t nodename;
01019         isc_result_t result = ISC_R_SUCCESS;
01020         int i;
01021 
01022         dns_name_init(&nodename, NULL);
01023 
01024         if (include_chain_end && chain->end != NULL) {
01025                 NODENAME(chain->end, &nodename);
01026                 result = dns_name_copy(&nodename, name, NULL);
01027                 if (result != ISC_R_SUCCESS)
01028                         return (result);
01029         } else
01030                 dns_name_reset(name);
01031 
01032         for (i = (int)chain->level_count - 1; i >= 0; i--) {
01033                 NODENAME(chain->levels[i], &nodename);
01034                 result = dns_name_concatenate(name, &nodename, name, NULL);
01035 
01036                 if (result != ISC_R_SUCCESS)
01037                         return (result);
01038         }
01039         return (result);
01040 }
01041 
01042 static inline isc_result_t
01043 move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
01044         do {
01045                 /*
01046                  * Go as far right and then down as much as possible,
01047                  * as long as the rightmost node has a down pointer.
01048                  */
01049                 while (RIGHT(node) != NULL)
01050                         node = RIGHT(node);
01051 
01052                 if (DOWN(node) == NULL)
01053                         break;
01054 
01055                 ADD_LEVEL(chain, node);
01056                 node = DOWN(node);
01057         } while (1);
01058 
01059         chain->end = node;
01060 
01061         return (ISC_R_SUCCESS);
01062 }
01063 
01064 /*
01065  * Add 'name' to tree, initializing its data pointer with 'data'.
01066  */
01067 
01068 isc_result_t
01069 dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
01070         /*
01071          * Does this thing have too many variables or what?
01072          */
01073         dns_rbtnode_t **root, *parent, *child, *current, *new_current;
01074         dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
01075         dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
01076         dns_offsets_t current_offsets;
01077         dns_namereln_t compared;
01078         isc_result_t result = ISC_R_SUCCESS;
01079         dns_rbtnodechain_t chain;
01080         unsigned int common_labels;
01081         unsigned int nlabels, hlabels;
01082         int order;
01083 
01084         REQUIRE(VALID_RBT(rbt));
01085         REQUIRE(dns_name_isabsolute(name));
01086         REQUIRE(nodep != NULL && *nodep == NULL);
01087 
01088         /*
01089          * Create a copy of the name so the original name structure is
01090          * not modified.
01091          */
01092         dns_fixedname_init(&fixedcopy);
01093         add_name = dns_fixedname_name(&fixedcopy);
01094         dns_name_clone(name, add_name);
01095 
01096         if (rbt->root == NULL) {
01097                 result = create_node(rbt->mctx, add_name, &new_current);
01098                 if (result == ISC_R_SUCCESS) {
01099                         rbt->nodecount++;
01100                         new_current->is_root = 1;
01101                         rbt->root = new_current;
01102                         *nodep = new_current;
01103                         hash_node(rbt, new_current, name);
01104                 }
01105                 return (result);
01106         }
01107 
01108         dns_rbtnodechain_init(&chain, rbt->mctx);
01109 
01110         dns_fixedname_init(&fixedprefix);
01111         dns_fixedname_init(&fixedsuffix);
01112         prefix = dns_fixedname_name(&fixedprefix);
01113         suffix = dns_fixedname_name(&fixedsuffix);
01114 
01115         root = &rbt->root;
01116         INSIST(IS_ROOT(*root));
01117         parent = NULL;
01118         current = NULL;
01119         child = *root;
01120         dns_name_init(&current_name, current_offsets);
01121         dns_fixedname_init(&fnewname);
01122         new_name = dns_fixedname_name(&fnewname);
01123         nlabels = dns_name_countlabels(name);
01124         hlabels = 0;
01125 
01126         do {
01127                 current = child;
01128 
01129                 NODENAME(current, &current_name);
01130                 compared = dns_name_fullcompare(add_name, &current_name,
01131                                                 &order, &common_labels);
01132 
01133                 if (compared == dns_namereln_equal) {
01134                         *nodep = current;
01135                         result = ISC_R_EXISTS;
01136                         break;
01137 
01138                 }
01139 
01140                 if (compared == dns_namereln_none) {
01141 
01142                         if (order < 0) {
01143                                 parent = current;
01144                                 child = LEFT(current);
01145 
01146                         } else if (order > 0) {
01147                                 parent = current;
01148                                 child = RIGHT(current);
01149 
01150                         }
01151 
01152                 } else {
01153                         /*
01154                          * This name has some suffix in common with the
01155                          * name at the current node.  If the name at
01156                          * the current node is shorter, that means the
01157                          * new name should be in a subtree.  If the
01158                          * name at the current node is longer, that means
01159                          * the down pointer to this tree should point
01160                          * to a new tree that has the common suffix, and
01161                          * the non-common parts of these two names should
01162                          * start a new tree.
01163                          */
01164                         hlabels += common_labels;
01165                         if (compared == dns_namereln_subdomain) {
01166                                 /*
01167                                  * All of the existing labels are in common,
01168                                  * so the new name is in a subtree.
01169                                  * Whack off the common labels for the
01170                                  * not-in-common part to be searched for
01171                                  * in the next level.
01172                                  */
01173                                 dns_name_split(add_name, common_labels,
01174                                                add_name, NULL);
01175 
01176                                 /*
01177                                  * Follow the down pointer (possibly NULL).
01178                                  */
01179                                 root = &DOWN(current);
01180 
01181                                 INSIST(*root == NULL ||
01182                                        (IS_ROOT(*root) &&
01183                                         PARENT(*root) == current));
01184 
01185                                 parent = NULL;
01186                                 child = DOWN(current);
01187                                 ADD_LEVEL(&chain, current);
01188 
01189                         } else {
01190                                 /*
01191                                  * The number of labels in common is fewer
01192                                  * than the number of labels at the current
01193                                  * node, so the current node must be adjusted
01194                                  * to have just the common suffix, and a down
01195                                  * pointer made to a new tree.
01196                                  */
01197 
01198                                 INSIST(compared == dns_namereln_commonancestor
01199                                        || compared == dns_namereln_contains);
01200 
01201                                 /*
01202                                  * Ensure the number of levels in the tree
01203                                  * does not exceed the number of logical
01204                                  * levels allowed by DNSSEC.
01205                                  *
01206                                  * XXXDCL need a better error result?
01207                                  *
01208                                  * XXXDCL Since chain ancestors were removed,
01209                                  * no longer used by addonlevel(),
01210                                  * this is the only real use of chains in the
01211                                  * function.  It could be done instead with
01212                                  * a simple integer variable, but I am pressed
01213                                  * for time.
01214                                  */
01215                                 if (chain.level_count ==
01216                                     (sizeof(chain.levels) /
01217                                      sizeof(*chain.levels))) {
01218                                         result = ISC_R_NOSPACE;
01219                                         break;
01220                                 }
01221 
01222                                 /*
01223                                  * Split the name into two parts, a prefix
01224                                  * which is the not-in-common parts of the
01225                                  * two names and a suffix that is the common
01226                                  * parts of them.
01227                                  */
01228                                 dns_name_split(&current_name, common_labels,
01229                                                prefix, suffix);
01230                                 result = create_node(rbt->mctx, suffix,
01231                                                      &new_current);
01232 
01233                                 if (result != ISC_R_SUCCESS)
01234                                         break;
01235 
01236                                 /*
01237                                  * Reproduce the tree attributes of the
01238                                  * current node.
01239                                  */
01240                                 new_current->is_root = current->is_root;
01241                                 if (current->nsec == DNS_RBT_NSEC_HAS_NSEC)
01242                                         new_current->nsec = DNS_RBT_NSEC_NORMAL;
01243                                 else
01244                                         new_current->nsec = current->nsec;
01245                                 PARENT(new_current)  = PARENT(current);
01246                                 LEFT(new_current)    = LEFT(current);
01247                                 RIGHT(new_current)   = RIGHT(current);
01248                                 COLOR(new_current)   = COLOR(current);
01249 
01250                                 /*
01251                                  * Fix pointers that were to the current node.
01252                                  */
01253                                 if (parent != NULL) {
01254                                         if (LEFT(parent) == current)
01255                                                 LEFT(parent) = new_current;
01256                                         else
01257                                                 RIGHT(parent) = new_current;
01258                                 }
01259                                 if (LEFT(new_current) != NULL)
01260                                         PARENT(LEFT(new_current)) =
01261                                                 new_current;
01262                                 if (RIGHT(new_current) != NULL)
01263                                         PARENT(RIGHT(new_current)) =
01264                                                 new_current;
01265                                 if (*root == current)
01266                                         *root = new_current;
01267 
01268                                 NAMELEN(current) = prefix->length;
01269                                 OFFSETLEN(current) = prefix->labels;
01270 
01271                                 /*
01272                                  * Set up the new root of the next level.
01273                                  * By definition it will not be the top
01274                                  * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
01275                                  */
01276                                 current->is_root = 1;
01277                                 PARENT(current) = new_current;
01278                                 DOWN(new_current) = current;
01279                                 root = &DOWN(new_current);
01280 
01281                                 ADD_LEVEL(&chain, new_current);
01282 
01283                                 LEFT(current) = NULL;
01284                                 RIGHT(current) = NULL;
01285 
01286                                 MAKE_BLACK(current);
01287                                 ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
01288 
01289                                 rbt->nodecount++;
01290                                 dns_name_getlabelsequence(name,
01291                                                           nlabels - hlabels,
01292                                                           hlabels, new_name);
01293                                 hash_node(rbt, new_current, new_name);
01294 
01295                                 if (common_labels ==
01296                                     dns_name_countlabels(add_name)) {
01297                                         /*
01298                                          * The name has been added by pushing
01299                                          * the not-in-common parts down to
01300                                          * a new level.
01301                                          */
01302                                         *nodep = new_current;
01303                                         return (ISC_R_SUCCESS);
01304 
01305                                 } else {
01306                                         /*
01307                                          * The current node has no data,
01308                                          * because it is just a placeholder.
01309                                          * Its data pointer is already NULL
01310                                          * from create_node()), so there's
01311                                          * nothing more to do to it.
01312                                          */
01313 
01314                                         /*
01315                                          * The not-in-common parts of the new
01316                                          * name will be inserted into the new
01317                                          * level following this loop (unless
01318                                          * result != ISC_R_SUCCESS, which
01319                                          * is tested after the loop ends).
01320                                          */
01321                                         dns_name_split(add_name, common_labels,
01322                                                        add_name, NULL);
01323 
01324                                         break;
01325                                 }
01326 
01327                         }
01328 
01329                 }
01330 
01331         } while (child != NULL);
01332 
01333         if (result == ISC_R_SUCCESS)
01334                 result = create_node(rbt->mctx, add_name, &new_current);
01335 
01336         if (result == ISC_R_SUCCESS) {
01337                 addonlevel(new_current, current, order, root);
01338                 rbt->nodecount++;
01339                 *nodep = new_current;
01340                 hash_node(rbt, new_current, name);
01341         }
01342 
01343         return (result);
01344 }
01345 
01346 /*
01347  * Add a name to the tree of trees, associating it with some data.
01348  */
01349 isc_result_t
01350 dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
01351         isc_result_t result;
01352         dns_rbtnode_t *node;
01353 
01354         REQUIRE(VALID_RBT(rbt));
01355         REQUIRE(dns_name_isabsolute(name));
01356 
01357         node = NULL;
01358 
01359         result = dns_rbt_addnode(rbt, name, &node);
01360 
01361         /*
01362          * dns_rbt_addnode will report the node exists even when
01363          * it does not have data associated with it, but the
01364          * dns_rbt_*name functions all behave depending on whether
01365          * there is data associated with a node.
01366          */
01367         if (result == ISC_R_SUCCESS ||
01368             (result == ISC_R_EXISTS && DATA(node) == NULL)) {
01369                 DATA(node) = data;
01370                 result = ISC_R_SUCCESS;
01371         }
01372 
01373         return (result);
01374 }
01375 
01376 /*
01377  * Find the node for "name" in the tree of trees.
01378  */
01379 isc_result_t
01380 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
01381                  dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
01382                  unsigned int options, dns_rbtfindcallback_t callback,
01383                  void *callback_arg)
01384 {
01385         dns_rbtnode_t *current, *last_compared, *current_root;
01386         dns_rbtnodechain_t localchain;
01387         dns_name_t *search_name, current_name, *callback_name;
01388         dns_fixedname_t fixedcallbackname, fixedsearchname;
01389         dns_namereln_t compared;
01390         isc_result_t result, saved_result;
01391         unsigned int common_labels;
01392         unsigned int hlabels = 0;
01393         int order;
01394 
01395         REQUIRE(VALID_RBT(rbt));
01396         REQUIRE(dns_name_isabsolute(name));
01397         REQUIRE(node != NULL && *node == NULL);
01398         REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
01399                 !=         (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
01400 
01401         /*
01402          * If there is a chain it needs to appear to be in a sane state,
01403          * otherwise a chain is still needed to generate foundname and
01404          * callback_name.
01405          */
01406         if (chain == NULL) {
01407                 options |= DNS_RBTFIND_NOPREDECESSOR;
01408                 chain = &localchain;
01409                 dns_rbtnodechain_init(chain, rbt->mctx);
01410         } else
01411                 dns_rbtnodechain_reset(chain);
01412 
01413         if (rbt->root == NULL)
01414                 return (ISC_R_NOTFOUND);
01415 
01416         /*
01417          * Appease GCC about variables it incorrectly thinks are
01418          * possibly used uninitialized.
01419          */
01420         compared = dns_namereln_none;
01421         last_compared = NULL;
01422         order = 0;
01423 
01424         dns_fixedname_init(&fixedcallbackname);
01425         callback_name = dns_fixedname_name(&fixedcallbackname);
01426 
01427         /*
01428          * search_name is the name segment being sought in each tree level.
01429          * By using a fixedname, the search_name will definitely have offsets
01430          * for use by any splitting.
01431          * By using dns_name_clone, no name data should be copied thanks to
01432          * the lack of bitstring labels.
01433          */
01434         dns_fixedname_init(&fixedsearchname);
01435         search_name = dns_fixedname_name(&fixedsearchname);
01436         dns_name_clone(name, search_name);
01437 
01438         dns_name_init(&current_name, NULL);
01439 
01440         saved_result = ISC_R_SUCCESS;
01441         current = rbt->root;
01442         current_root = rbt->root;
01443 
01444         while (current != NULL) {
01445                 NODENAME(current, &current_name);
01446                 compared = dns_name_fullcompare(search_name, &current_name,
01447                                                 &order, &common_labels);
01448                 /*
01449                  * last_compared is used as a shortcut to start (or
01450                  * continue rather) finding the stop-node of the search
01451                  * when hashing was used (see much below in this
01452                  * function).
01453                  */
01454                 last_compared = current;
01455 
01456                 if (compared == dns_namereln_equal)
01457                         break;
01458 
01459                 if (compared == dns_namereln_none) {
01460 #ifdef DNS_RBT_USEHASH
01461                         /*
01462                          * Here, current is pointing at a subtree root
01463                          * node. We try to find a matching node using
01464                          * the hashtable. We can get one of 3 results
01465                          * here: (a) we locate the matching node, (b) we
01466                          * find a node to which the current node has a
01467                          * subdomain relation, (c) we fail to find (a)
01468                          * or (b).
01469                          */
01470 
01471                         dns_name_t hash_name;
01472                         dns_rbtnode_t *hnode;
01473                         dns_rbtnode_t *up_current;
01474                         unsigned int nlabels;
01475                         unsigned int tlabels = 1;
01476                         unsigned int hash;
01477 
01478                         /*
01479                          * If there is no hash table, hashing can't be done.
01480                          */
01481                         if (rbt->hashtable == NULL)
01482                                 goto nohash;
01483 
01484                         /*
01485                          * The case of current != current_root, that
01486                          * means a left or right pointer was followed,
01487                          * only happens when the algorithm fell through to
01488                          * the traditional binary search because of a
01489                          * bitstring label.  Since we dropped the bitstring
01490                          * support, this should not happen.
01491                          */
01492                         INSIST(current == current_root);
01493 
01494                         nlabels = dns_name_countlabels(search_name);
01495 
01496                         /*
01497                          * current_root is the root of the current level, so
01498                          * it's parent is the same as it's "up" pointer.
01499                          */
01500                         up_current = PARENT(current_root);
01501                         dns_name_init(&hash_name, NULL);
01502 
01503                 hashagain:
01504                         /*
01505                          * Compute the hash over the full absolute
01506                          * name. Look for the smallest suffix match at
01507                          * this tree level (hlevel), and then at every
01508                          * iteration, look for the next smallest suffix
01509                          * match (add another subdomain label to the
01510                          * absolute name being hashed).
01511                          */
01512                         dns_name_getlabelsequence(name,
01513                                                   nlabels - tlabels,
01514                                                   hlabels + tlabels,
01515                                                   &hash_name);
01516                         hash = dns_name_fullhash(&hash_name, ISC_FALSE);
01517                         dns_name_getlabelsequence(search_name,
01518                                                   nlabels - tlabels,
01519                                                   tlabels, &hash_name);
01520 
01521                         /*
01522                          * Walk all the nodes in the hash bucket pointed
01523                          * by the computed hash value.
01524                          */
01525                         for (hnode = rbt->hashtable[hash % rbt->hashsize];
01526                              hnode != NULL;
01527                              hnode = hnode->hashnext)
01528                         {
01529                                 dns_name_t hnode_name;
01530 
01531                                 if (hash != HASHVAL(hnode))
01532                                         continue;
01533                                 /*
01534                                  * This checks that the hashed label
01535                                  * sequence being looked up is at the
01536                                  * same tree level, so that we don't
01537                                  * match a labelsequence from some other
01538                                  * subdomain.
01539                                  */
01540                                 if (get_upper_node(hnode) != up_current)
01541                                         continue;
01542 
01543                                 dns_name_init(&hnode_name, NULL);
01544                                 NODENAME(hnode, &hnode_name);
01545                                 if (dns_name_equal(&hnode_name, &hash_name))
01546                                         break;
01547                         }
01548 
01549                         if (hnode != NULL) {
01550                                 current = hnode;
01551                                 /*
01552                                  * This is an optimization.  If hashing found
01553                                  * the right node, the next call to
01554                                  * dns_name_fullcompare() would obviously
01555                                  * return _equal or _subdomain.  Determine
01556                                  * which of those would be the case by
01557                                  * checking if the full name was hashed.  Then
01558                                  * make it look like dns_name_fullcompare
01559                                  * was called and jump to the right place.
01560                                  */
01561                                 if (tlabels == nlabels) {
01562                                         compared = dns_namereln_equal;
01563                                         break;
01564                                 } else {
01565                                         common_labels = tlabels;
01566                                         compared = dns_namereln_subdomain;
01567                                         goto subdomain;
01568                                 }
01569                         }
01570 
01571                         if (tlabels++ < nlabels)
01572                                 goto hashagain;
01573 
01574                         /*
01575                          * All of the labels have been tried against the hash
01576                          * table.  Since we dropped the support of bitstring
01577                          * labels, the name isn't in the table.
01578                          */
01579                         current = NULL;
01580                         continue;
01581 
01582                 nohash:
01583 #endif /* DNS_RBT_USEHASH */
01584                         /*
01585                          * Standard binary search tree movement.
01586                          */
01587                         if (order < 0)
01588                                 current = LEFT(current);
01589                         else
01590                                 current = RIGHT(current);
01591 
01592                 } else {
01593                         /*
01594                          * The names have some common suffix labels.
01595                          *
01596                          * If the number in common are equal in length to
01597                          * the current node's name length, then follow the
01598                          * down pointer and search in the new tree.
01599                          */
01600                         if (compared == dns_namereln_subdomain) {
01601 #ifdef DNS_RBT_USEHASH
01602                 subdomain:
01603 #endif
01604                                 /*
01605                                  * Whack off the current node's common parts
01606                                  * for the name to search in the next level.
01607                                  */
01608                                 dns_name_split(search_name, common_labels,
01609                                                search_name, NULL);
01610                                 hlabels += common_labels;
01611                                 /*
01612                                  * This might be the closest enclosing name.
01613                                  */
01614                                 if (DATA(current) != NULL ||
01615                                     (options & DNS_RBTFIND_EMPTYDATA) != 0)
01616                                         *node = current;
01617 
01618                                 /*
01619                                  * Point the chain to the next level.   This
01620                                  * needs to be done before 'current' is pointed
01621                                  * there because the callback in the next
01622                                  * block of code needs the current 'current',
01623                                  * but in the event the callback requests that
01624                                  * the search be stopped then the
01625                                  * DNS_R_PARTIALMATCH code at the end of this
01626                                  * function needs the chain pointed to the
01627                                  * next level.
01628                                  */
01629                                 ADD_LEVEL(chain, current);
01630 
01631                                 /*
01632                                  * The caller may want to interrupt the
01633                                  * downward search when certain special nodes
01634                                  * are traversed.  If this is a special node,
01635                                  * the callback is used to learn what the
01636                                  * caller wants to do.
01637                                  */
01638                                 if (callback != NULL &&
01639                                     FINDCALLBACK(current)) {
01640                                         result = chain_name(chain,
01641                                                             callback_name,
01642                                                             ISC_FALSE);
01643                                         if (result != ISC_R_SUCCESS) {
01644                                                 dns_rbtnodechain_reset(chain);
01645                                                 return (result);
01646                                         }
01647 
01648                                         result = (callback)(current,
01649                                                             callback_name,
01650                                                             callback_arg);
01651                                         if (result != DNS_R_CONTINUE) {
01652                                                 saved_result = result;
01653                                                 /*
01654                                                  * Treat this node as if it
01655                                                  * had no down pointer.
01656                                                  */
01657                                                 current = NULL;
01658                                                 break;
01659                                         }
01660                                 }
01661 
01662                                 /*
01663                                  * Finally, head to the next tree level.
01664                                  */
01665                                 current = DOWN(current);
01666                                 current_root = current;
01667 
01668                         } else {
01669                                 /*
01670                                  * Though there are labels in common, the
01671                                  * entire name at this node is not common
01672                                  * with the search name so the search
01673                                  * name does not exist in the tree.
01674                                  */
01675                                 INSIST(compared == dns_namereln_commonancestor
01676                                        || compared == dns_namereln_contains);
01677 
01678                                 current = NULL;
01679                         }
01680                 }
01681         }
01682 
01683         /*
01684          * If current is not NULL, NOEXACT is not disallowing exact matches,
01685          * and either the node has data or an empty node is ok, return
01686          * ISC_R_SUCCESS to indicate an exact match.
01687          */
01688         if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
01689             (DATA(current) != NULL ||
01690              (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
01691                 /*
01692                  * Found an exact match.
01693                  */
01694                 chain->end = current;
01695                 chain->level_matches = chain->level_count;
01696 
01697                 if (foundname != NULL)
01698                         result = chain_name(chain, foundname, ISC_TRUE);
01699                 else
01700                         result = ISC_R_SUCCESS;
01701 
01702                 if (result == ISC_R_SUCCESS) {
01703                         *node = current;
01704                         result = saved_result;
01705                 } else
01706                         *node = NULL;
01707         } else {
01708                 /*
01709                  * Did not find an exact match (or did not want one).
01710                  */
01711                 if (*node != NULL) {
01712                         /*
01713                          * ... but found a partially matching superdomain.
01714                          * Unwind the chain to the partial match node
01715                          * to set level_matches to the level above the node,
01716                          * and then to derive the name.
01717                          *
01718                          * chain->level_count is guaranteed to be at least 1
01719                          * here because by definition of finding a superdomain,
01720                          * the chain is pointed to at least the first subtree.
01721                          */
01722                         chain->level_matches = chain->level_count - 1;
01723 
01724                         while (chain->levels[chain->level_matches] != *node) {
01725                                 INSIST(chain->level_matches > 0);
01726                                 chain->level_matches--;
01727                         }
01728 
01729                         if (foundname != NULL) {
01730                                 unsigned int saved_count = chain->level_count;
01731 
01732                                 chain->level_count = chain->level_matches + 1;
01733 
01734                                 result = chain_name(chain, foundname,
01735                                                     ISC_FALSE);
01736 
01737                                 chain->level_count = saved_count;
01738                         } else
01739                                 result = ISC_R_SUCCESS;
01740 
01741                         if (result == ISC_R_SUCCESS)
01742                                 result = DNS_R_PARTIALMATCH;
01743 
01744                 } else
01745                         result = ISC_R_NOTFOUND;
01746 
01747                 if (current != NULL) {
01748                         /*
01749                          * There was an exact match but either
01750                          * DNS_RBTFIND_NOEXACT was set, or
01751                          * DNS_RBTFIND_EMPTYDATA was set and the node had no
01752                          * data.  A policy decision was made to set the
01753                          * chain to the exact match, but this is subject
01754                          * to change if it becomes apparent that something
01755                          * else would be more useful.  It is important that
01756                          * this case is handled here, because the predecessor
01757                          * setting code below assumes the match was not exact.
01758                          */
01759                         INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
01760                                ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
01761                                 DATA(current) == NULL));
01762                         chain->end = current;
01763 
01764                 } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
01765                         /*
01766                          * Ensure the chain points nowhere.
01767                          */
01768                         chain->end = NULL;
01769 
01770                 } else {
01771                         /*
01772                          * Since there was no exact match, the chain argument
01773                          * needs to be pointed at the DNSSEC predecessor of
01774                          * the search name.
01775                          */
01776                         if (compared == dns_namereln_subdomain) {
01777                                 /*
01778                                  * Attempted to follow a down pointer that was
01779                                  * NULL, which means the searched for name was
01780                                  * a subdomain of a terminal name in the tree.
01781                                  * Since there are no existing subdomains to
01782                                  * order against, the terminal name is the
01783                                  * predecessor.
01784                                  */
01785                                 INSIST(chain->level_count > 0);
01786                                 INSIST(chain->level_matches <
01787                                        chain->level_count);
01788                                 chain->end =
01789                                         chain->levels[--chain->level_count];
01790 
01791                         } else {
01792                                 isc_result_t result2;
01793 
01794                                 /*
01795                                  * Point current to the node that stopped
01796                                  * the search.
01797                                  *
01798                                  * With the hashing modification that has been
01799                                  * added to the algorithm, the stop node of a
01800                                  * standard binary search is not known.  So it
01801                                  * has to be found.  There is probably a more
01802                                  * clever way of doing this.
01803                                  *
01804                                  * The assignment of current to NULL when
01805                                  * the relationship is *not* dns_namereln_none,
01806                                  * even though it later gets set to the same
01807                                  * last_compared anyway, is simply to not push
01808                                  * the while loop in one more level of
01809                                  * indentation.
01810                                  */
01811                                 if (compared == dns_namereln_none)
01812                                         current = last_compared;
01813                                 else
01814                                         current = NULL;
01815 
01816                                 while (current != NULL) {
01817                                         NODENAME(current, &current_name);
01818                                         compared = dns_name_fullcompare(
01819                                                                 search_name,
01820                                                                 &current_name,
01821                                                                 &order,
01822                                                                 &common_labels);
01823                                         POST(compared);
01824 
01825                                         last_compared = current;
01826 
01827                                         /*
01828                                          * Standard binary search movement.
01829                                          */
01830                                         if (order < 0)
01831                                                 current = LEFT(current);
01832                                         else
01833                                                 current = RIGHT(current);
01834 
01835                                 }
01836 
01837                                 current = last_compared;
01838 
01839                                 /*
01840                                  * Reached a point within a level tree that
01841                                  * positively indicates the name is not
01842                                  * present, but the stop node could be either
01843                                  * less than the desired name (order > 0) or
01844                                  * greater than the desired name (order < 0).
01845                                  *
01846                                  * If the stop node is less, it is not
01847                                  * necessarily the predecessor.  If the stop
01848                                  * node has a down pointer, then the real
01849                                  * predecessor is at the end of a level below
01850                                  * (not necessarily the next level).
01851                                  * Move down levels until the rightmost node
01852                                  * does not have a down pointer.
01853                                  *
01854                                  * When the stop node is greater, it is
01855                                  * the successor.  All the logic for finding
01856                                  * the predecessor is handily encapsulated
01857                                  * in dns_rbtnodechain_prev.  In the event
01858                                  * that the search name is less than anything
01859                                  * else in the tree, the chain is reset.
01860                                  * XXX DCL What is the best way for the caller
01861                                  *         to know that the search name has
01862                                  *         no predecessor?
01863                                  */
01864 
01865 
01866                                 if (order > 0) {
01867                                         if (DOWN(current) != NULL) {
01868                                                 ADD_LEVEL(chain, current);
01869 
01870                                                 result2 =
01871                                                       move_chain_to_last(chain,
01872                                                                 DOWN(current));
01873 
01874                                                 if (result2 != ISC_R_SUCCESS)
01875                                                         result = result2;
01876                                         } else
01877                                                 /*
01878                                                  * Ah, the pure and simple
01879                                                  * case.  The stop node is the
01880                                                  * predecessor.
01881                                                  */
01882                                                 chain->end = current;
01883 
01884                                 } else {
01885                                         INSIST(order < 0);
01886 
01887                                         chain->end = current;
01888 
01889                                         result2 = dns_rbtnodechain_prev(chain,
01890                                                                         NULL,
01891                                                                         NULL);
01892                                         if (result2 == ISC_R_SUCCESS ||
01893                                             result2 == DNS_R_NEWORIGIN)
01894                                                 ;       /* Nothing. */
01895                                         else if (result2 == ISC_R_NOMORE)
01896                                                 /*
01897                                                  * There is no predecessor.
01898                                                  */
01899                                                 dns_rbtnodechain_reset(chain);
01900                                         else
01901                                                 result = result2;
01902                                 }
01903 
01904                         }
01905                 }
01906         }
01907 
01908         ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
01909 
01910         return (result);
01911 }
01912 
01913 /*
01914  * Get the data pointer associated with 'name'.
01915  */
01916 isc_result_t
01917 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
01918                  dns_name_t *foundname, void **data) {
01919         dns_rbtnode_t *node = NULL;
01920         isc_result_t result;
01921 
01922         REQUIRE(data != NULL && *data == NULL);
01923 
01924         result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
01925                                   options, NULL, NULL);
01926 
01927         if (node != NULL &&
01928             (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
01929                 *data = DATA(node);
01930         else
01931                 result = ISC_R_NOTFOUND;
01932 
01933         return (result);
01934 }
01935 
01936 /*
01937  * Delete a name from the tree of trees.
01938  */
01939 isc_result_t
01940 dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
01941         dns_rbtnode_t *node = NULL;
01942         isc_result_t result;
01943 
01944         REQUIRE(VALID_RBT(rbt));
01945         REQUIRE(dns_name_isabsolute(name));
01946 
01947         /*
01948          * First, find the node.
01949          *
01950          * When searching, the name might not have an exact match:
01951          * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
01952          * elements of a tree, which would make layer 1 a single
01953          * node tree of "b.a.com" and layer 2 a three node tree of
01954          * a, b, and c.  Deleting a.com would find only a partial depth
01955          * match in the first layer.  Should it be a requirement that
01956          * that the name to be deleted have data?  For now, it is.
01957          *
01958          * ->dirty, ->locknum and ->references are ignored; they are
01959          * solely the province of rbtdb.c.
01960          */
01961         result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
01962                                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
01963 
01964         if (result == ISC_R_SUCCESS) {
01965                 if (DATA(node) != NULL)
01966                         result = dns_rbt_deletenode(rbt, node, recurse);
01967                 else
01968                         result = ISC_R_NOTFOUND;
01969 
01970         } else if (result == DNS_R_PARTIALMATCH)
01971                 result = ISC_R_NOTFOUND;
01972 
01973         return (result);
01974 }
01975 
01976 /*
01977  * Remove a node from the tree of trees.
01978  *
01979  * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing
01980  * a sequence of additions to be deletions will not generally get the
01981  * tree back to the state it started in.  For example, if the addition
01982  * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level,
01983  * then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
01984  * restoring "a.b.c".  The RBT *used* to do this kind of rejoining, but it
01985  * turned out to be a bad idea because it could corrupt an active nodechain
01986  * that had "b.c" as one of its levels -- and the RBT has no idea what
01987  * nodechains are in use by callers, so it can't even *try* to helpfully
01988  * fix them up (which would probably be doomed to failure anyway).
01989  *
01990  * Similarly, it is possible to leave the tree in a state where a supposedly
01991  * deleted node still exists.  The first case of this is obvious; take
01992  * the tree which has "b.c" on one level, pointing to "a".  Now deleted "b.c".
01993  * It was just established in the previous paragraph why we can't pull "a"
01994  * back up to its parent level.  But what happens when "a" then gets deleted?
01995  * "b.c" is left hanging around without data or children.  This condition
01996  * is actually pretty easy to detect, but ... should it really be removed?
01997  * Is a chain pointing to it?  An iterator?  Who knows!  (Note that the
01998  * references structure member cannot be looked at because it is private to
01999  * rbtdb.)  This is ugly and makes me unhappy, but after hours of trying to
02000  * make it more aesthetically proper and getting nowhere, this is the way it
02001  * is going to stay until such time as it proves to be a *real* problem.
02002  *
02003  * Finally, for reference, note that the original routine that did node
02004  * joining was called join_nodes().  It has been excised, living now only
02005  * in the CVS history, but comments have been left behind that point to it just
02006  * in case someone wants to muck with this some more.
02007  *
02008  * The one positive aspect of all of this is that joining used to have a
02009  * case where it might fail.  Without trying to join, now this function always
02010  * succeeds. It still returns isc_result_t, though, so the API wouldn't change.
02011  */
02012 isc_result_t
02013 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
02014 {
02015         dns_rbtnode_t *parent;
02016 
02017         REQUIRE(VALID_RBT(rbt));
02018         REQUIRE(DNS_RBTNODE_VALID(node));
02019         INSIST(rbt->nodecount != 0);
02020 
02021         if (DOWN(node) != NULL) {
02022                 if (recurse)
02023                         RUNTIME_CHECK(deletetree(rbt, DOWN(node))
02024                                       == ISC_R_SUCCESS);
02025                 else {
02026                         if (DATA(node) != NULL && rbt->data_deleter != NULL)
02027                                 rbt->data_deleter(DATA(node), rbt->deleter_arg);
02028                         DATA(node) = NULL;
02029 
02030                         /*
02031                          * Since there is at least one node below this one and
02032                          * no recursion was requested, the deletion is
02033                          * complete.  The down node from this node might be all
02034                          * by itself on a single level, so join_nodes() could
02035                          * be used to collapse the tree (with all the caveats
02036                          * of the comment at the start of this function).
02037                          */
02038                         return (ISC_R_SUCCESS);
02039                 }
02040         }
02041 
02042         /*
02043          * Note the node that points to the level of the node that is being
02044          * deleted.  If the deleted node is the top level, parent will be set
02045          * to NULL.
02046          */
02047         parent = get_upper_node(node);
02048 
02049         /*
02050          * This node now has no down pointer (either because it didn't
02051          * have one to start, or because it was recursively removed).
02052          * So now the node needs to be removed from this level.
02053          */
02054         deletefromlevel(node, parent == NULL ? &rbt->root : &DOWN(parent));
02055 
02056         if (DATA(node) != NULL && rbt->data_deleter != NULL)
02057                 rbt->data_deleter(DATA(node), rbt->deleter_arg);
02058 
02059         unhash_node(rbt, node);
02060 #if DNS_RBT_USEMAGIC
02061         node->magic = 0;
02062 #endif
02063         dns_rbtnode_refdestroy(node);
02064 
02065         freenode(rbt, &node);
02066 
02067         /*
02068          * There are now two special cases that can exist that would
02069          * not have existed if the tree had been created using only
02070          * the names that now exist in it.  (This is all related to
02071          * join_nodes() as described in this function's introductory comment.)
02072          * Both cases exist when the deleted node's parent (the node
02073          * that pointed to the deleted node's level) is not null but
02074          * it has no data:  parent != NULL && DATA(parent) == NULL.
02075          *
02076          * The first case is that the deleted node was the last on its level:
02077          * DOWN(parent) == NULL.  This case can only exist if the parent was
02078          * previously deleted -- and so now, apparently, the parent should go
02079          * away.  That can't be done though because there might be external
02080          * references to it, such as through a nodechain.
02081          *
02082          * The other case also involves a parent with no data, but with the
02083          * deleted node being the next-to-last node instead of the last:
02084          * LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.
02085          * Presumably now the remaining node on the level should be joined
02086          * with the parent, but it's already been described why that can't be
02087          * done.
02088          */
02089 
02090         /*
02091          * This function never fails.
02092          */
02093         return (ISC_R_SUCCESS);
02094 }
02095 
02096 void
02097 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
02098 
02099         REQUIRE(DNS_RBTNODE_VALID(node));
02100         REQUIRE(name != NULL);
02101         REQUIRE(name->offsets == NULL);
02102 
02103         NODENAME(node, name);
02104 }
02105 
02106 isc_result_t
02107 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
02108         dns_name_t current;
02109         isc_result_t result;
02110 
02111         REQUIRE(DNS_RBTNODE_VALID(node));
02112         REQUIRE(name != NULL);
02113         REQUIRE(name->buffer != NULL);
02114 
02115         dns_name_init(&current, NULL);
02116         dns_name_reset(name);
02117 
02118         do {
02119                 INSIST(node != NULL);
02120 
02121                 NODENAME(node, &current);
02122 
02123                 result = dns_name_concatenate(name, &current, name, NULL);
02124                 if (result != ISC_R_SUCCESS)
02125                         break;
02126 
02127                 node = get_upper_node(node);
02128         } while (! dns_name_isabsolute(name));
02129 
02130         return (result);
02131 }
02132 
02133 char *
02134 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
02135 {
02136         dns_fixedname_t fixedname;
02137         dns_name_t *name;
02138         isc_result_t result;
02139 
02140         REQUIRE(DNS_RBTNODE_VALID(node));
02141         REQUIRE(printname != NULL);
02142 
02143         dns_fixedname_init(&fixedname);
02144         name = dns_fixedname_name(&fixedname);
02145         result = dns_rbt_fullnamefromnode(node, name);
02146         if (result == ISC_R_SUCCESS)
02147                 dns_name_format(name, printname, size);
02148         else
02149                 snprintf(printname, size, "<error building name: %s>",
02150                          dns_result_totext(result));
02151 
02152         return (printname);
02153 }
02154 
02155 static isc_result_t
02156 create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
02157         dns_rbtnode_t *node;
02158         isc_region_t region;
02159         unsigned int labels;
02160         size_t nodelen;
02161 
02162         REQUIRE(name->offsets != NULL);
02163 
02164         dns_name_toregion(name, &region);
02165         labels = dns_name_countlabels(name);
02166         ENSURE(labels > 0);
02167 
02168         /*
02169          * Allocate space for the node structure, the name, and the offsets.
02170          */
02171         nodelen = sizeof(dns_rbtnode_t) + region.length + labels + 1;
02172         node = (dns_rbtnode_t *)isc_mem_get(mctx, nodelen);
02173         if (node == NULL)
02174                 return (ISC_R_NOMEMORY);
02175         memset(node, 0, nodelen);
02176 
02177         node->is_root = 0;
02178         PARENT(node) = NULL;
02179         RIGHT(node) = NULL;
02180         LEFT(node) = NULL;
02181         DOWN(node) = NULL;
02182         DATA(node) = NULL;
02183         node->is_mmapped = 0;
02184         node->down_is_relative = 0;
02185         node->left_is_relative = 0;
02186         node->right_is_relative = 0;
02187         node->parent_is_relative = 0;
02188         node->data_is_relative = 0;
02189         node->rpz = 0;
02190 
02191 #ifdef DNS_RBT_USEHASH
02192         HASHNEXT(node) = NULL;
02193         HASHVAL(node) = 0;
02194 #endif
02195 
02196         ISC_LINK_INIT(node, deadlink);
02197 
02198         LOCKNUM(node) = 0;
02199         WILD(node) = 0;
02200         DIRTY(node) = 0;
02201         dns_rbtnode_refinit(node, 0);
02202         node->find_callback = 0;
02203         node->nsec = DNS_RBT_NSEC_NORMAL;
02204 
02205         MAKE_BLACK(node);
02206 
02207         /*
02208          * The following is stored to make reconstructing a name from the
02209          * stored value in the node easy:  the length of the name, the number
02210          * of labels, whether the name is absolute or not, the name itself,
02211          * and the name's offsets table.
02212          *
02213          * XXX RTH
02214          *      The offsets table could be made smaller by eliminating the
02215          *      first offset, which is always 0.  This requires changes to
02216          *      lib/dns/name.c.
02217          *
02218          * Note: OLDOFFSETLEN *must* be assigned *after* OLDNAMELEN is assigned
02219          *       as it uses OLDNAMELEN.
02220          */
02221         OLDNAMELEN(node) = NAMELEN(node) = region.length;
02222         OLDOFFSETLEN(node) = OFFSETLEN(node) = labels;
02223         ATTRS(node) = name->attributes;
02224 
02225         memmove(NAME(node), region.base, region.length);
02226         memmove(OFFSETS(node), name->offsets, labels);
02227 
02228 #if DNS_RBT_USEMAGIC
02229         node->magic = DNS_RBTNODE_MAGIC;
02230 #endif
02231         *nodep = node;
02232 
02233         return (ISC_R_SUCCESS);
02234 }
02235 
02236 #ifdef DNS_RBT_USEHASH
02237 static inline void
02238 hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
02239         unsigned int hash;
02240 
02241         REQUIRE(name != NULL);
02242 
02243         HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
02244 
02245         hash = HASHVAL(node) % rbt->hashsize;
02246         HASHNEXT(node) = rbt->hashtable[hash];
02247 
02248         rbt->hashtable[hash] = node;
02249 }
02250 
02251 static isc_result_t
02252 inithash(dns_rbt_t *rbt) {
02253         unsigned int bytes;
02254 
02255         rbt->hashsize = RBT_HASH_SIZE;
02256         bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);
02257         rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
02258 
02259         if (rbt->hashtable == NULL)
02260                 return (ISC_R_NOMEMORY);
02261 
02262         memset(rbt->hashtable, 0, bytes);
02263 
02264         return (ISC_R_SUCCESS);
02265 }
02266 
02267 static void
02268 rehash(dns_rbt_t *rbt, unsigned int newcount) {
02269         unsigned int oldsize;
02270         dns_rbtnode_t **oldtable;
02271         dns_rbtnode_t *node;
02272         unsigned int hash;
02273         unsigned int i;
02274 
02275         oldsize = rbt->hashsize;
02276         oldtable = rbt->hashtable;
02277         do {
02278                 rbt->hashsize = rbt->hashsize * 2 + 1;
02279         } while (newcount >= (rbt->hashsize * 3));
02280         rbt->hashtable = isc_mem_get(rbt->mctx,
02281                                      rbt->hashsize * sizeof(dns_rbtnode_t *));
02282         if (rbt->hashtable == NULL) {
02283                 rbt->hashtable = oldtable;
02284                 rbt->hashsize = oldsize;
02285                 return;
02286         }
02287 
02288         INSIST(rbt->hashsize > 0);
02289 
02290         for (i = 0; i < rbt->hashsize; i++)
02291                 rbt->hashtable[i] = NULL;
02292 
02293         for (i = 0; i < oldsize; i++) {
02294                 node = oldtable[i];
02295                 while (node != NULL) {
02296                         hash = HASHVAL(node) % rbt->hashsize;
02297                         oldtable[i] = HASHNEXT(node);
02298                         HASHNEXT(node) = rbt->hashtable[hash];
02299                         rbt->hashtable[hash] = node;
02300                         node = oldtable[i];
02301                 }
02302         }
02303 
02304         isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
02305 }
02306 
02307 static inline void
02308 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
02309         REQUIRE(DNS_RBTNODE_VALID(node));
02310 
02311         if (rbt->nodecount >= (rbt->hashsize * 3))
02312                 rehash(rbt, rbt->nodecount);
02313 
02314         hash_add_node(rbt, node, name);
02315 }
02316 
02317 static inline void
02318 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
02319         unsigned int bucket;
02320         dns_rbtnode_t *bucket_node;
02321 
02322         REQUIRE(DNS_RBTNODE_VALID(node));
02323 
02324         if (rbt->hashtable != NULL) {
02325                 bucket = HASHVAL(node) % rbt->hashsize;
02326                 bucket_node = rbt->hashtable[bucket];
02327 
02328                 if (bucket_node == node)
02329                         rbt->hashtable[bucket] = HASHNEXT(node);
02330                 else {
02331                         while (HASHNEXT(bucket_node) != node) {
02332                                 INSIST(HASHNEXT(bucket_node) != NULL);
02333                                 bucket_node = HASHNEXT(bucket_node);
02334                         }
02335                         HASHNEXT(bucket_node) = HASHNEXT(node);
02336                 }
02337         }
02338 }
02339 #endif /* DNS_RBT_USEHASH */
02340 
02341 static inline void
02342 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
02343         dns_rbtnode_t *child;
02344 
02345         REQUIRE(DNS_RBTNODE_VALID(node));
02346         REQUIRE(rootp != NULL);
02347 
02348         child = RIGHT(node);
02349         INSIST(child != NULL);
02350 
02351         RIGHT(node) = LEFT(child);
02352         if (LEFT(child) != NULL)
02353                 PARENT(LEFT(child)) = node;
02354         LEFT(child) = node;
02355 
02356         if (child != NULL)
02357                 PARENT(child) = PARENT(node);
02358 
02359         if (IS_ROOT(node)) {
02360                 *rootp = child;
02361                 child->is_root = 1;
02362                 node->is_root = 0;
02363 
02364         } else {
02365                 if (LEFT(PARENT(node)) == node)
02366                         LEFT(PARENT(node)) = child;
02367                 else
02368                         RIGHT(PARENT(node)) = child;
02369         }
02370 
02371         PARENT(node) = child;
02372 }
02373 
02374 static inline void
02375 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
02376         dns_rbtnode_t *child;
02377 
02378         REQUIRE(DNS_RBTNODE_VALID(node));
02379         REQUIRE(rootp != NULL);
02380 
02381         child = LEFT(node);
02382         INSIST(child != NULL);
02383 
02384         LEFT(node) = RIGHT(child);
02385         if (RIGHT(child) != NULL)
02386                 PARENT(RIGHT(child)) = node;
02387         RIGHT(child) = node;
02388 
02389         if (child != NULL)
02390                 PARENT(child) = PARENT(node);
02391 
02392         if (IS_ROOT(node)) {
02393                 *rootp = child;
02394                 child->is_root = 1;
02395                 node->is_root = 0;
02396 
02397         } else {
02398                 if (LEFT(PARENT(node)) == node)
02399                         LEFT(PARENT(node)) = child;
02400                 else
02401                         RIGHT(PARENT(node)) = child;
02402         }
02403 
02404         PARENT(node) = child;
02405 }
02406 
02407 /*
02408  * This is the real workhorse of the insertion code, because it does the
02409  * true red/black tree on a single level.
02410  */
02411 static void
02412 addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
02413            dns_rbtnode_t **rootp)
02414 {
02415         dns_rbtnode_t *child, *root, *parent, *grandparent;
02416         dns_name_t add_name, current_name;
02417         dns_offsets_t add_offsets, current_offsets;
02418 
02419         REQUIRE(rootp != NULL);
02420         REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
02421                 RIGHT(node) == NULL);
02422         REQUIRE(current != NULL);
02423 
02424         root = *rootp;
02425         if (root == NULL) {
02426                 /*
02427                  * First node of a level.
02428                  */
02429                 MAKE_BLACK(node);
02430                 node->is_root = 1;
02431                 PARENT(node) = current;
02432                 *rootp = node;
02433                 return;
02434         }
02435 
02436         child = root;
02437         POST(child);
02438 
02439         dns_name_init(&add_name, add_offsets);
02440         NODENAME(node, &add_name);
02441 
02442         dns_name_init(&current_name, current_offsets);
02443         NODENAME(current, &current_name);
02444 
02445         if (order < 0) {
02446                 INSIST(LEFT(current) == NULL);
02447                 LEFT(current) = node;
02448         } else {
02449                 INSIST(RIGHT(current) == NULL);
02450                 RIGHT(current) = node;
02451         }
02452 
02453         INSIST(PARENT(node) == NULL);
02454         PARENT(node) = current;
02455 
02456         MAKE_RED(node);
02457 
02458         while (node != root && IS_RED(PARENT(node))) {
02459                 /*
02460                  * XXXDCL could do away with separate parent and grandparent
02461                  * variables.  They are vestiges of the days before parent
02462                  * pointers.  However, they make the code a little clearer.
02463                  */
02464 
02465                 parent = PARENT(node);
02466                 grandparent = PARENT(parent);
02467 
02468                 if (parent == LEFT(grandparent)) {
02469                         child = RIGHT(grandparent);
02470                         if (child != NULL && IS_RED(child)) {
02471                                 MAKE_BLACK(parent);
02472                                 MAKE_BLACK(child);
02473                                 MAKE_RED(grandparent);
02474                                 node = grandparent;
02475                         } else {
02476                                 if (node == RIGHT(parent)) {
02477                                         rotate_left(parent, &root);
02478                                         node = parent;
02479                                         parent = PARENT(node);
02480                                         grandparent = PARENT(parent);
02481                                 }
02482                                 MAKE_BLACK(parent);
02483                                 MAKE_RED(grandparent);
02484                                 rotate_right(grandparent, &root);
02485                         }
02486                 } else {
02487                         child = LEFT(grandparent);
02488                         if (child != NULL && IS_RED(child)) {
02489                                 MAKE_BLACK(parent);
02490                                 MAKE_BLACK(child);
02491                                 MAKE_RED(grandparent);
02492                                 node = grandparent;
02493                         } else {
02494                                 if (node == LEFT(parent)) {
02495                                         rotate_right(parent, &root);
02496                                         node = parent;
02497                                         parent = PARENT(node);
02498                                         grandparent = PARENT(parent);
02499                                 }
02500                                 MAKE_BLACK(parent);
02501                                 MAKE_RED(grandparent);
02502                                 rotate_left(grandparent, &root);
02503                         }
02504                 }
02505         }
02506 
02507         MAKE_BLACK(root);
02508         ENSURE(IS_ROOT(root));
02509         *rootp = root;
02510 
02511         return;
02512 }
02513 
02514 /*
02515  * This is the real workhorse of the deletion code, because it does the
02516  * true red/black tree on a single level.
02517  */
02518 static void
02519 deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
02520         dns_rbtnode_t *child, *sibling, *parent;
02521         dns_rbtnode_t *successor;
02522 
02523         REQUIRE(delete != NULL);
02524 
02525         /*
02526          * Verify that the parent history is (apparently) correct.
02527          */
02528         INSIST((IS_ROOT(delete) && *rootp == delete) ||
02529                (! IS_ROOT(delete) &&
02530                 (LEFT(PARENT(delete)) == delete ||
02531                  RIGHT(PARENT(delete)) == delete)));
02532 
02533         child = NULL;
02534 
02535         if (LEFT(delete) == NULL) {
02536                 if (RIGHT(delete) == NULL) {
02537                         if (IS_ROOT(delete)) {
02538                                 /*
02539                                  * This is the only item in the tree.
02540                                  */
02541                                 *rootp = NULL;
02542                                 return;
02543                         }
02544                 } else
02545                         /*
02546                          * This node has one child, on the right.
02547                          */
02548                         child = RIGHT(delete);
02549 
02550         } else if (RIGHT(delete) == NULL)
02551                 /*
02552                  * This node has one child, on the left.
02553                  */
02554                 child = LEFT(delete);
02555         else {
02556                 dns_rbtnode_t holder, *tmp = &holder;
02557 
02558                 /*
02559                  * This node has two children, so it cannot be directly
02560                  * deleted.  Find its immediate in-order successor and
02561                  * move it to this location, then do the deletion at the
02562                  * old site of the successor.
02563                  */
02564                 successor = RIGHT(delete);
02565                 while (LEFT(successor) != NULL)
02566                         successor = LEFT(successor);
02567 
02568                 /*
02569                  * The successor cannot possibly have a left child;
02570                  * if there is any child, it is on the right.
02571                  */
02572                 if (RIGHT(successor) != NULL)
02573                         child = RIGHT(successor);
02574 
02575                 /*
02576                  * Swap the two nodes; it would be simpler to just replace
02577                  * the value being deleted with that of the successor,
02578                  * but this rigamarole is done so the caller has complete
02579                  * control over the pointers (and memory allocation) of
02580                  * all of nodes.  If just the key value were removed from
02581                  * the tree, the pointer to the node would be unchanged.
02582                  */
02583 
02584                 /*
02585                  * First, put the successor in the tree location of the
02586                  * node to be deleted.  Save its existing tree pointer
02587                  * information, which will be needed when linking up
02588                  * delete to the successor's old location.
02589                  */
02590                 memmove(tmp, successor, sizeof(dns_rbtnode_t));
02591 
02592                 if (IS_ROOT(delete)) {
02593                         *rootp = successor;
02594                         successor->is_root = ISC_TRUE;
02595                         delete->is_root = ISC_FALSE;
02596 
02597                 } else
02598                         if (LEFT(PARENT(delete)) == delete)
02599                                 LEFT(PARENT(delete)) = successor;
02600                         else
02601                                 RIGHT(PARENT(delete)) = successor;
02602 
02603                 PARENT(successor) = PARENT(delete);
02604                 LEFT(successor)   = LEFT(delete);
02605                 RIGHT(successor)  = RIGHT(delete);
02606                 COLOR(successor)  = COLOR(delete);
02607 
02608                 if (LEFT(successor) != NULL)
02609                         PARENT(LEFT(successor)) = successor;
02610                 if (RIGHT(successor) != successor)
02611                         PARENT(RIGHT(successor)) = successor;
02612 
02613                 /*
02614                  * Now relink the node to be deleted into the
02615                  * successor's previous tree location.  PARENT(tmp)
02616                  * is the successor's original parent.
02617                  */
02618                 INSIST(! IS_ROOT(delete));
02619 
02620                 if (PARENT(tmp) == delete) {
02621                         /*
02622                          * Node being deleted was successor's parent.
02623                          */
02624                         RIGHT(successor) = delete;
02625                         PARENT(delete) = successor;
02626 
02627                 } else {
02628                         LEFT(PARENT(tmp)) = delete;
02629                         PARENT(delete) = PARENT(tmp);
02630                 }
02631 
02632                 /*
02633                  * Original location of successor node has no left.
02634                  */
02635                 LEFT(delete)   = NULL;
02636                 RIGHT(delete)  = RIGHT(tmp);
02637                 COLOR(delete)  = COLOR(tmp);
02638         }
02639 
02640         /*
02641          * Remove the node by removing the links from its parent.
02642          */
02643         if (! IS_ROOT(delete)) {
02644                 if (LEFT(PARENT(delete)) == delete)
02645                         LEFT(PARENT(delete)) = child;
02646                 else
02647                         RIGHT(PARENT(delete)) = child;
02648 
02649                 if (child != NULL)
02650                         PARENT(child) = PARENT(delete);
02651 
02652         } else {
02653                 /*
02654                  * This is the root being deleted, and at this point
02655                  * it is known to have just one child.
02656                  */
02657                 *rootp = child;
02658                 child->is_root = 1;
02659                 PARENT(child) = PARENT(delete);
02660         }
02661 
02662         /*
02663          * Fix color violations.
02664          */
02665         if (IS_BLACK(delete)) {
02666                 parent = PARENT(delete);
02667 
02668                 while (child != *rootp && IS_BLACK(child)) {
02669                         INSIST(child == NULL || ! IS_ROOT(child));
02670 
02671                         if (LEFT(parent) == child) {
02672                                 sibling = RIGHT(parent);
02673 
02674                                 if (IS_RED(sibling)) {
02675                                         MAKE_BLACK(sibling);
02676                                         MAKE_RED(parent);
02677                                         rotate_left(parent, rootp);
02678                                         sibling = RIGHT(parent);
02679                                 }
02680 
02681                                 INSIST(sibling != NULL);
02682 
02683                                 if (IS_BLACK(LEFT(sibling)) &&
02684                                     IS_BLACK(RIGHT(sibling))) {
02685                                         MAKE_RED(sibling);
02686                                         child = parent;
02687 
02688                                 } else {
02689 
02690                                         if (IS_BLACK(RIGHT(sibling))) {
02691                                                 MAKE_BLACK(LEFT(sibling));
02692                                                 MAKE_RED(sibling);
02693                                                 rotate_right(sibling, rootp);
02694                                                 sibling = RIGHT(parent);
02695                                         }
02696 
02697                                         COLOR(sibling) = COLOR(parent);
02698                                         MAKE_BLACK(parent);
02699                                         INSIST(RIGHT(sibling) != NULL);
02700                                         MAKE_BLACK(RIGHT(sibling));
02701                                         rotate_left(parent, rootp);
02702                                         child = *rootp;
02703                                 }
02704 
02705                         } else {
02706                                 /*
02707                                  * Child is parent's right child.
02708                                  * Everything is done the same as above,
02709                                  * except mirrored.
02710                                  */
02711                                 sibling = LEFT(parent);
02712 
02713                                 if (IS_RED(sibling)) {
02714                                         MAKE_BLACK(sibling);
02715                                         MAKE_RED(parent);
02716                                         rotate_right(parent, rootp);
02717                                         sibling = LEFT(parent);
02718                                 }
02719 
02720                                 INSIST(sibling != NULL);
02721 
02722                                 if (IS_BLACK(LEFT(sibling)) &&
02723                                     IS_BLACK(RIGHT(sibling))) {
02724                                         MAKE_RED(sibling);
02725                                         child = parent;
02726 
02727                                 } else {
02728                                         if (IS_BLACK(LEFT(sibling))) {
02729                                                 MAKE_BLACK(RIGHT(sibling));
02730                                                 MAKE_RED(sibling);
02731                                                 rotate_left(sibling, rootp);
02732                                                 sibling = LEFT(parent);
02733                                         }
02734 
02735                                         COLOR(sibling) = COLOR(parent);
02736                                         MAKE_BLACK(parent);
02737                                         INSIST(LEFT(sibling) != NULL);
02738                                         MAKE_BLACK(LEFT(sibling));
02739                                         rotate_right(parent, rootp);
02740                                         child = *rootp;
02741                                 }
02742                         }
02743 
02744                         parent = PARENT(child);
02745                 }
02746 
02747                 if (IS_RED(child))
02748                         MAKE_BLACK(child);
02749         }
02750 }
02751 
02752 /*
02753  * This should only be used on the root of a tree, because no color fixup
02754  * is done at all.
02755  *
02756  * NOTE: No root pointer maintenance is done, because the function is only
02757  * used for two cases:
02758  * + deleting everything DOWN from a node that is itself being deleted, and
02759  * + deleting the entire tree of trees from dns_rbt_destroy.
02760  * In each case, the root pointer is no longer relevant, so there
02761  * is no need for a root parameter to this function.
02762  *
02763  * If the function is ever intended to be used to delete something where
02764  * a pointer needs to be told that this tree no longer exists,
02765  * this function would need to adjusted accordingly.
02766  */
02767 static isc_result_t
02768 deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) {
02769         isc_result_t result = ISC_R_SUCCESS;
02770 
02771         REQUIRE(VALID_RBT(rbt));
02772 
02773         if (node == NULL)
02774                 return (result);
02775 
02776         if (LEFT(node) != NULL) {
02777                 result = deletetree(rbt, LEFT(node));
02778                 if (result != ISC_R_SUCCESS)
02779                         goto done;
02780                 LEFT(node) = NULL;
02781         }
02782         if (RIGHT(node) != NULL) {
02783                 result = deletetree(rbt, RIGHT(node));
02784                 if (result != ISC_R_SUCCESS)
02785                         goto done;
02786                 RIGHT(node) = NULL;
02787         }
02788         if (DOWN(node) != NULL) {
02789                 result = deletetree(rbt, DOWN(node));
02790                 if (result != ISC_R_SUCCESS)
02791                         goto done;
02792                 DOWN(node) = NULL;
02793         }
02794  done:
02795         if (result != ISC_R_SUCCESS)
02796                 return (result);
02797 
02798         if (DATA(node) != NULL && rbt->data_deleter != NULL)
02799                 rbt->data_deleter(DATA(node), rbt->deleter_arg);
02800 
02801         unhash_node(rbt, node);
02802 #if DNS_RBT_USEMAGIC
02803         node->magic = 0;
02804 #endif
02805 
02806         freenode(rbt, &node);
02807         return (result);
02808 }
02809 
02810 static void
02811 freenode(dns_rbt_t *rbt, dns_rbtnode_t **nodep) {
02812         dns_rbtnode_t *node = *nodep;
02813 
02814         if (node->is_mmapped == 0) {
02815                 isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
02816         }
02817         *nodep = NULL;
02818 
02819         rbt->nodecount--;
02820 }
02821 
02822 static void
02823 deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, dns_rbtnode_t **nodep) {
02824         dns_rbtnode_t *parent;
02825         dns_rbtnode_t *node = *nodep;
02826 
02827         REQUIRE(VALID_RBT(rbt));
02828 
02829  again:
02830         if (node == NULL) {
02831                 *nodep = NULL;
02832                 return;
02833         }
02834 
02835  traverse:
02836         if (LEFT(node) != NULL) {
02837                 node = LEFT(node);
02838                 goto traverse;
02839         }
02840         if (DOWN(node) != NULL) {
02841                 node = DOWN(node);
02842                 goto traverse;
02843         }
02844 
02845         if (DATA(node) != NULL && rbt->data_deleter != NULL)
02846                 rbt->data_deleter(DATA(node), rbt->deleter_arg);
02847 
02848         /*
02849          * Note: we don't call unhash_node() here as we are destroying
02850          * the complete rbt tree.
02851          */
02852 #if DNS_RBT_USEMAGIC
02853         node->magic = 0;
02854 #endif
02855         parent = PARENT(node);
02856         if (RIGHT(node) != NULL)
02857                 PARENT(RIGHT(node)) = parent;
02858         if (parent != NULL) {
02859                 if (LEFT(parent) == node)
02860                         LEFT(parent) = RIGHT(node);
02861                 else if (DOWN(parent) == node)
02862                         DOWN(parent) = RIGHT(node);
02863         } else
02864                 parent = RIGHT(node);
02865 
02866         freenode(rbt, &node);
02867 
02868         node = parent;
02869         if (quantum != 0 && --quantum == 0) {
02870                 *nodep = node;
02871                 return;
02872         }
02873         goto again;
02874 }
02875 
02876 static size_t
02877 getheight_helper(dns_rbtnode_t *node) {
02878         size_t dl, dr;
02879         size_t this_height, down_height;
02880 
02881         if (node == NULL)
02882                 return (0);
02883 
02884         dl = getheight_helper(LEFT(node));
02885         dr = getheight_helper(RIGHT(node));
02886 
02887         this_height = ISC_MAX(dl + 1, dr + 1);
02888         down_height = getheight_helper(DOWN(node));
02889 
02890         return (ISC_MAX(this_height, down_height));
02891 }
02892 
02893 size_t
02894 dns__rbt_getheight(dns_rbt_t *rbt) {
02895         return (getheight_helper(rbt->root));
02896 }
02897 
02898 static isc_boolean_t
02899 check_properties_helper(dns_rbtnode_t *node) {
02900         if (node == NULL)
02901                 return (ISC_TRUE);
02902 
02903         if (IS_RED(node)) {
02904                 /* Root nodes must be BLACK. */
02905                 if (IS_ROOT(node))
02906                         return (ISC_FALSE);
02907 
02908                 /* Both children of RED nodes must be BLACK. */
02909                 if (IS_RED(LEFT(node)) || IS_RED(RIGHT(node)))
02910                         return (ISC_FALSE);
02911         }
02912 
02913         /* If node is assigned to the down_ pointer of its parent, it is
02914          * a subtree root and must have the flag set.
02915          */
02916         if (((!PARENT(node)) ||
02917              (DOWN(PARENT(node)) == node)) &&
02918             (!IS_ROOT(node)))
02919         {
02920                 return (ISC_FALSE);
02921         }
02922 
02923         /* Repeat tests with this node's children. */
02924         return (check_properties_helper(LEFT(node)) &&
02925                 check_properties_helper(RIGHT(node)) &&
02926                 check_properties_helper(DOWN(node)));
02927 }
02928 
02929 static isc_boolean_t
02930 check_black_distance_helper(dns_rbtnode_t *node, size_t *distance) {
02931         size_t dl, dr, dd;
02932 
02933         if (node == NULL) {
02934                 *distance = 1;
02935                 return (ISC_TRUE);
02936         }
02937 
02938         if (!check_black_distance_helper(LEFT(node), &dl))
02939                 return (ISC_FALSE);
02940 
02941         if (!check_black_distance_helper(RIGHT(node), &dr))
02942                 return (ISC_FALSE);
02943 
02944         if (!check_black_distance_helper(DOWN(node), &dd))
02945                 return (ISC_FALSE);
02946 
02947         /* Left and right side black node counts must match. */
02948         if (dl != dr)
02949                 return (ISC_FALSE);
02950 
02951         if (IS_BLACK(node))
02952                 dl++;
02953 
02954         *distance = dl;
02955 
02956         return (ISC_TRUE);
02957 }
02958 
02959 isc_boolean_t
02960 dns__rbt_checkproperties(dns_rbt_t *rbt) {
02961         size_t dd;
02962 
02963         if (!check_properties_helper(rbt->root))
02964                 return (ISC_FALSE);
02965 
02966         /* Path from a given node to all its leaves must contain the
02967          * same number of BLACK child nodes. This is done separately
02968          * here instead of inside check_properties_helper() as
02969          * it would take (n log n) complexity otherwise.
02970          */
02971         return (check_black_distance_helper(rbt->root, &dd));
02972 }
02973 
02974 static void
02975 dns_rbt_indent(FILE *f, int depth) {
02976         int i;
02977 
02978         fprintf(f, "%4d ", depth);
02979 
02980         for (i = 0; i < depth; i++)
02981                 fprintf(f, "- ");
02982 }
02983 
02984 void
02985 dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f) {
02986         fprintf(f, "Node info for nodename: ");
02987         printnodename(n, ISC_TRUE, f);
02988         fprintf(f, "\n");
02989 
02990         fprintf(f, "n = %p\n", n);
02991 
02992         fprintf(f, "Relative pointers: %s%s%s%s%s\n",
02993                         (n->parent_is_relative == 1 ? " P" : ""),
02994                         (n->right_is_relative == 1 ? " R" : ""),
02995                         (n->left_is_relative == 1 ? " L" : ""),
02996                         (n->down_is_relative == 1 ? " D" : ""),
02997                         (n->data_is_relative == 1 ? " T" : ""));
02998 
02999         fprintf(f, "node lock address = %d\n", n->locknum);
03000 
03001         fprintf(f, "Parent: %p\n", n->parent);
03002         fprintf(f, "Right: %p\n", n->right);
03003         fprintf(f, "Left: %p\n", n->left);
03004         fprintf(f, "Down: %p\n", n->down);
03005         fprintf(f, "daTa: %p\n", n->data);
03006 }
03007 
03008 static void
03009 printnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f) {
03010         isc_region_t r;
03011         dns_name_t name;
03012         char buffer[DNS_NAME_FORMATSIZE];
03013         dns_offsets_t offsets;
03014 
03015         r.length = NAMELEN(node);
03016         r.base = NAME(node);
03017 
03018         dns_name_init(&name, offsets);
03019         dns_name_fromregion(&name, &r);
03020 
03021         dns_name_format(&name, buffer, sizeof(buffer));
03022 
03023         if (quoted)
03024                 fprintf(f, "\"%s\"", buffer);
03025         else
03026                 fprintf(f, "%s", buffer);
03027 }
03028 
03029 static void
03030 print_text_helper(dns_rbtnode_t *root, dns_rbtnode_t *parent,
03031                   int depth, const char *direction,
03032                   void (*data_printer)(FILE *, void *), FILE *f)
03033 {
03034         dns_rbt_indent(f, depth);
03035 
03036         if (root != NULL) {
03037                 printnodename(root, ISC_TRUE, f);
03038                 fprintf(f, " (%s, %s", direction,
03039                         IS_RED(root) ? "RED" : "BLACK");
03040 
03041                 if ((! IS_ROOT(root) && PARENT(root) != parent) ||
03042                     (  IS_ROOT(root) && depth > 0 &&
03043                        DOWN(PARENT(root)) != root)) {
03044 
03045                         fprintf(f, " (BAD parent pointer! -> ");
03046                         if (PARENT(root) != NULL)
03047                                 printnodename(PARENT(root), ISC_TRUE, f);
03048                         else
03049                                 fprintf(f, "NULL");
03050                         fprintf(f, ")");
03051                 }
03052 
03053                 fprintf(f, ")");
03054 
03055                 if (root->data != NULL && data_printer != NULL) {
03056                         fprintf(f, " data@%p: ", root->data);
03057                         data_printer(f, root->data);
03058                 }
03059                 fprintf(f, "\n");
03060 
03061                 depth++;
03062 
03063                 if (IS_RED(root) && IS_RED(LEFT(root)))
03064                         fprintf(f, "** Red/Red color violation on left\n");
03065                 print_text_helper(LEFT(root), root, depth, "left",
03066                                           data_printer, f);
03067 
03068                 if (IS_RED(root) && IS_RED(RIGHT(root)))
03069                         fprintf(f, "** Red/Red color violation on right\n");
03070                 print_text_helper(RIGHT(root), root, depth, "right",
03071                                           data_printer, f);
03072 
03073                 print_text_helper(DOWN(root), NULL, depth, "down",
03074                                           data_printer, f);
03075         } else {
03076                 fprintf(f, "NULL (%s)\n", direction);
03077         }
03078 }
03079 
03080 void
03081 dns_rbt_printtext(dns_rbt_t *rbt,
03082                   void (*data_printer)(FILE *, void *), FILE *f)
03083 {
03084         REQUIRE(VALID_RBT(rbt));
03085 
03086         print_text_helper(rbt->root, NULL, 0, "root", data_printer, f);
03087 }
03088 
03089 static int
03090 print_dot_helper(dns_rbtnode_t *node, unsigned int *nodecount,
03091                  isc_boolean_t show_pointers, FILE *f)
03092 {
03093         unsigned int l, r, d;
03094 
03095         if (node == NULL)
03096                 return (0);
03097 
03098         l = print_dot_helper(LEFT(node), nodecount, show_pointers, f);
03099         r = print_dot_helper(RIGHT(node), nodecount, show_pointers, f);
03100         d = print_dot_helper(DOWN(node), nodecount, show_pointers, f);
03101 
03102         *nodecount += 1;
03103 
03104         fprintf(f, "node%u[label = \"<f0> |<f1> ", *nodecount);
03105         printnodename(node, ISC_FALSE, f);
03106         fprintf(f, "|<f2>");
03107 
03108         if (show_pointers)
03109                 fprintf(f, "|<f3> n=%p|<f4> p=%p", node, PARENT(node));
03110 
03111         fprintf(f, "\"] [");
03112 
03113         if (IS_RED(node))
03114                 fprintf(f, "color=red");
03115         else
03116                 fprintf(f, "color=black");
03117 
03118         /* XXXMUKS: verify that IS_ROOT() indicates subtree root and not
03119          * forest root.
03120          */
03121         if (IS_ROOT(node))
03122                 fprintf(f, ",penwidth=3");
03123 
03124         if (IS_EMPTY(node))
03125                 fprintf(f, ",style=filled,fillcolor=lightgrey");
03126 
03127         fprintf(f, "];\n");
03128 
03129         if (LEFT(node) != NULL)
03130                 fprintf(f, "\"node%u\":f0 -> \"node%u\":f1;\n", *nodecount, l);
03131 
03132         if (DOWN(node) != NULL)
03133                 fprintf(f, "\"node%u\":f1 -> \"node%u\":f1 [penwidth=5];\n",
03134                         *nodecount, d);
03135 
03136         if (RIGHT(node) != NULL)
03137                 fprintf(f, "\"node%u\":f2 -> \"node%u\":f1;\n", *nodecount, r);
03138 
03139         return (*nodecount);
03140 }
03141 
03142 void
03143 dns_rbt_printdot(dns_rbt_t *rbt, isc_boolean_t show_pointers, FILE *f) {
03144         unsigned int nodecount = 0;
03145 
03146         REQUIRE(VALID_RBT(rbt));
03147 
03148         fprintf(f, "digraph g {\n");
03149         fprintf(f, "node [shape = record,height=.1];\n");
03150         print_dot_helper(rbt->root, &nodecount, show_pointers, f);
03151         fprintf(f, "}\n");
03152 }
03153 
03154 /*
03155  * Chain Functions
03156  */
03157 
03158 void
03159 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
03160 
03161         REQUIRE(chain != NULL);
03162 
03163         /*
03164          * Initialize 'chain'.
03165          */
03166         chain->mctx = mctx;
03167         chain->end = NULL;
03168         chain->level_count = 0;
03169         chain->level_matches = 0;
03170         memset(chain->levels, 0, sizeof(chain->levels));
03171 
03172         chain->magic = CHAIN_MAGIC;
03173 }
03174 
03175 isc_result_t
03176 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
03177                          dns_name_t *origin, dns_rbtnode_t **node)
03178 {
03179         isc_result_t result = ISC_R_SUCCESS;
03180 
03181         REQUIRE(VALID_CHAIN(chain));
03182 
03183         if (node != NULL)
03184                 *node = chain->end;
03185 
03186         if (chain->end == NULL)
03187                 return (ISC_R_NOTFOUND);
03188 
03189         if (name != NULL) {
03190                 NODENAME(chain->end, name);
03191 
03192                 if (chain->level_count == 0) {
03193                         /*
03194                          * Names in the top level tree are all absolute.
03195                          * Always make 'name' relative.
03196                          */
03197                         INSIST(dns_name_isabsolute(name));
03198 
03199                         /*
03200                          * This is cheaper than dns_name_getlabelsequence().
03201                          */
03202                         name->labels--;
03203                         name->length--;
03204                         name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
03205                 }
03206         }
03207 
03208         if (origin != NULL) {
03209                 if (chain->level_count > 0)
03210                         result = chain_name(chain, origin, ISC_FALSE);
03211                 else
03212                         result = dns_name_copy(dns_rootname, origin, NULL);
03213         }
03214 
03215         return (result);
03216 }
03217 
03218 isc_result_t
03219 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
03220                       dns_name_t *origin)
03221 {
03222         dns_rbtnode_t *current, *previous, *predecessor;
03223         isc_result_t result = ISC_R_SUCCESS;
03224         isc_boolean_t new_origin = ISC_FALSE;
03225 
03226         REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
03227 
03228         predecessor = NULL;
03229 
03230         current = chain->end;
03231 
03232         if (LEFT(current) != NULL) {
03233                 /*
03234                  * Moving left one then right as far as possible is the
03235                  * previous node, at least for this level.
03236                  */
03237                 current = LEFT(current);
03238 
03239                 while (RIGHT(current) != NULL)
03240                         current = RIGHT(current);
03241 
03242                 predecessor = current;
03243 
03244         } else {
03245                 /*
03246                  * No left links, so move toward the root.  If at any point on
03247                  * the way there the link from parent to child is a right
03248                  * link, then the parent is the previous node, at least
03249                  * for this level.
03250                  */
03251                 while (! IS_ROOT(current)) {
03252                         previous = current;
03253                         current = PARENT(current);
03254 
03255                         if (RIGHT(current) == previous) {
03256                                 predecessor = current;
03257                                 break;
03258                         }
03259                 }
03260         }
03261 
03262         if (predecessor != NULL) {
03263                 /*
03264                  * Found a predecessor node in this level.  It might not
03265                  * really be the predecessor, however.
03266                  */
03267                 if (DOWN(predecessor) != NULL) {
03268                         /*
03269                          * The predecessor is really down at least one level.
03270                          * Go down and as far right as possible, and repeat
03271                          * as long as the rightmost node has a down pointer.
03272                          */
03273                         do {
03274                                 /*
03275                                  * XXX DCL Need to do something about origins
03276                                  * here. See whether to go down, and if so
03277                                  * whether it is truly what Bob calls a
03278                                  * new origin.
03279                                  */
03280                                 ADD_LEVEL(chain, predecessor);
03281                                 predecessor = DOWN(predecessor);
03282 
03283                                 /* XXX DCL duplicated from above; clever
03284                                  * way to unduplicate? */
03285 
03286                                 while (RIGHT(predecessor) != NULL)
03287                                         predecessor = RIGHT(predecessor);
03288                         } while (DOWN(predecessor) != NULL);
03289 
03290                         /* XXX DCL probably needs work on the concept */
03291                         if (origin != NULL)
03292                                 new_origin = ISC_TRUE;
03293                 }
03294 
03295         } else if (chain->level_count > 0) {
03296                 /*
03297                  * Dang, didn't find a predecessor in this level.
03298                  * Got to the root of this level without having traversed
03299                  * any right links.  Ascend the tree one level; the
03300                  * node that points to this tree is the predecessor.
03301                  */
03302                 INSIST(chain->level_count > 0 && IS_ROOT(current));
03303                 predecessor = chain->levels[--chain->level_count];
03304 
03305                 /* XXX DCL probably needs work on the concept */
03306                 /*
03307                  * Don't declare an origin change when the new origin is "."
03308                  * at the top level tree, because "." is declared as the origin
03309                  * for the second level tree.
03310                  */
03311                 if (origin != NULL &&
03312                     (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
03313                         new_origin = ISC_TRUE;
03314         }
03315 
03316         if (predecessor != NULL) {
03317                 chain->end = predecessor;
03318 
03319                 if (new_origin) {
03320                         result = dns_rbtnodechain_current(chain, name, origin,
03321                                                           NULL);
03322                         if (result == ISC_R_SUCCESS)
03323                                 result = DNS_R_NEWORIGIN;
03324 
03325                 } else
03326                         result = dns_rbtnodechain_current(chain, name, NULL,
03327                                                           NULL);
03328 
03329         } else
03330                 result = ISC_R_NOMORE;
03331 
03332         return (result);
03333 }
03334 
03335 isc_result_t
03336 dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
03337                       dns_name_t *origin)
03338 {
03339         dns_rbtnode_t *current, *successor;
03340         isc_result_t result = ISC_R_SUCCESS;
03341         isc_boolean_t new_origin = ISC_FALSE;
03342 
03343         REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
03344 
03345         successor = NULL;
03346 
03347         current = chain->end;
03348 
03349         if (DOWN(current) != NULL) {
03350                 /*
03351                  * Don't declare an origin change when the new origin is "."
03352                  * at the second level tree, because "." is already declared
03353                  * as the origin for the top level tree.
03354                  */
03355                 if (chain->level_count > 0 ||
03356                     OFFSETLEN(current) > 1)
03357                         new_origin = ISC_TRUE;
03358 
03359                 ADD_LEVEL(chain, current);
03360                 current = DOWN(current);
03361 
03362                 while (LEFT(current) != NULL)
03363                         current = LEFT(current);
03364 
03365                 successor = current;
03366         }
03367 
03368         if (successor != NULL) {
03369                 chain->end = successor;
03370 
03371                 /*
03372                  * It is not necessary to use dns_rbtnodechain_current like
03373                  * the other functions because this function will never
03374                  * find a node in the topmost level.  This is because the
03375                  * root level will never be more than one name, and everything
03376                  * in the megatree is a successor to that node, down at
03377                  * the second level or below.
03378                  */
03379 
03380                 if (name != NULL)
03381                         NODENAME(chain->end, name);
03382 
03383                 if (new_origin) {
03384                         if (origin != NULL)
03385                                 result = chain_name(chain, origin, ISC_FALSE);
03386 
03387                         if (result == ISC_R_SUCCESS)
03388                                 result = DNS_R_NEWORIGIN;
03389 
03390                 } else
03391                         result = ISC_R_SUCCESS;
03392 
03393         } else
03394                 result = ISC_R_NOMORE;
03395 
03396         return (result);
03397 }
03398 
03399 isc_result_t
03400 dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) {
03401         dns_rbtnode_t *current, *previous, *successor;
03402         isc_result_t result = ISC_R_SUCCESS;
03403 
03404         REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
03405 
03406         successor = NULL;
03407 
03408         current = chain->end;
03409 
03410         if (RIGHT(current) == NULL) {
03411                 while (! IS_ROOT(current)) {
03412                         previous = current;
03413                         current = PARENT(current);
03414 
03415                         if (LEFT(current) == previous) {
03416                                 successor = current;
03417                                 break;
03418                         }
03419                 }
03420         } else {
03421                 current = RIGHT(current);
03422 
03423                 while (LEFT(current) != NULL)
03424                         current = LEFT(current);
03425 
03426                 successor = current;
03427         }
03428 
03429         if (successor != NULL) {
03430                 chain->end = successor;
03431 
03432                 if (name != NULL)
03433                         NODENAME(chain->end, name);
03434 
03435                 result = ISC_R_SUCCESS;
03436         } else
03437                 result = ISC_R_NOMORE;
03438 
03439         return (result);
03440 }
03441 
03442 isc_result_t
03443 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
03444                       dns_name_t *origin)
03445 {
03446         dns_rbtnode_t *current, *previous, *successor;
03447         isc_result_t result = ISC_R_SUCCESS;
03448         isc_boolean_t new_origin = ISC_FALSE;
03449 
03450         REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
03451 
03452         successor = NULL;
03453 
03454         current = chain->end;
03455 
03456         /*
03457          * If there is a level below this node, the next node is the leftmost
03458          * node of the next level.
03459          */
03460         if (DOWN(current) != NULL) {
03461                 /*
03462                  * Don't declare an origin change when the new origin is "."
03463                  * at the second level tree, because "." is already declared
03464                  * as the origin for the top level tree.
03465                  */
03466                 if (chain->level_count > 0 ||
03467                     OFFSETLEN(current) > 1)
03468                         new_origin = ISC_TRUE;
03469 
03470                 ADD_LEVEL(chain, current);
03471                 current = DOWN(current);
03472 
03473                 while (LEFT(current) != NULL)
03474                         current = LEFT(current);
03475 
03476                 successor = current;
03477 
03478         } else if (RIGHT(current) == NULL) {
03479                 /*
03480                  * The successor is up, either in this level or a previous one.
03481                  * Head back toward the root of the tree, looking for any path
03482                  * that was via a left link; the successor is the node that has
03483                  * that left link.  In the event the root of the level is
03484                  * reached without having traversed any left links, ascend one
03485                  * level and look for either a right link off the point of
03486                  * ascent, or search for a left link upward again, repeating
03487                  * ascends until either case is true.
03488                  */
03489                 do {
03490                         while (! IS_ROOT(current)) {
03491                                 previous = current;
03492                                 current = PARENT(current);
03493 
03494                                 if (LEFT(current) == previous) {
03495                                         successor = current;
03496                                         break;
03497                                 }
03498                         }
03499 
03500                         if (successor == NULL) {
03501                                 /*
03502                                  * Reached the root without having traversed
03503                                  * any left pointers, so this level is done.
03504                                  */
03505                                 if (chain->level_count == 0)
03506                                         break;
03507 
03508                                 current = chain->levels[--chain->level_count];
03509                                 new_origin = ISC_TRUE;
03510 
03511                                 if (RIGHT(current) != NULL)
03512                                         break;
03513                         }
03514                 } while (successor == NULL);
03515         }
03516 
03517         if (successor == NULL && RIGHT(current) != NULL) {
03518                 current = RIGHT(current);
03519 
03520                 while (LEFT(current) != NULL)
03521                         current = LEFT(current);
03522 
03523                 successor = current;
03524         }
03525 
03526         if (successor != NULL) {
03527                 chain->end = successor;
03528 
03529                 /*
03530                  * It is not necessary to use dns_rbtnodechain_current like
03531                  * the other functions because this function will never
03532                  * find a node in the topmost level.  This is because the
03533                  * root level will never be more than one name, and everything
03534                  * in the megatree is a successor to that node, down at
03535                  * the second level or below.
03536                  */
03537 
03538                 if (name != NULL)
03539                         NODENAME(chain->end, name);
03540 
03541                 if (new_origin) {
03542                         if (origin != NULL)
03543                                 result = chain_name(chain, origin, ISC_FALSE);
03544 
03545                         if (result == ISC_R_SUCCESS)
03546                                 result = DNS_R_NEWORIGIN;
03547 
03548                 } else
03549                         result = ISC_R_SUCCESS;
03550 
03551         } else
03552                 result = ISC_R_NOMORE;
03553 
03554         return (result);
03555 }
03556 
03557 isc_result_t
03558 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
03559                        dns_name_t *name, dns_name_t *origin)
03560 
03561 {
03562         isc_result_t result;
03563 
03564         REQUIRE(VALID_RBT(rbt));
03565         REQUIRE(VALID_CHAIN(chain));
03566 
03567         dns_rbtnodechain_reset(chain);
03568 
03569         chain->end = rbt->root;
03570 
03571         result = dns_rbtnodechain_current(chain, name, origin, NULL);
03572 
03573         if (result == ISC_R_SUCCESS)
03574                 result = DNS_R_NEWORIGIN;
03575 
03576         return (result);
03577 }
03578 
03579 isc_result_t
03580 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
03581                        dns_name_t *name, dns_name_t *origin)
03582 
03583 {
03584         isc_result_t result;
03585 
03586         REQUIRE(VALID_RBT(rbt));
03587         REQUIRE(VALID_CHAIN(chain));
03588 
03589         dns_rbtnodechain_reset(chain);
03590 
03591         result = move_chain_to_last(chain, rbt->root);
03592         if (result != ISC_R_SUCCESS)
03593                 return (result);
03594 
03595         result = dns_rbtnodechain_current(chain, name, origin, NULL);
03596 
03597         if (result == ISC_R_SUCCESS)
03598                 result = DNS_R_NEWORIGIN;
03599 
03600         return (result);
03601 }
03602 
03603 
03604 void
03605 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
03606 
03607         REQUIRE(VALID_CHAIN(chain));
03608 
03609         /*
03610          * Free any dynamic storage associated with 'chain', and then
03611          * reinitialize 'chain'.
03612          */
03613         chain->end = NULL;
03614         chain->level_count = 0;
03615         chain->level_matches = 0;
03616 }
03617 
03618 void
03619 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
03620         /*
03621          * Free any dynamic storage associated with 'chain', and then
03622          * invalidate 'chain'.
03623          */
03624 
03625         dns_rbtnodechain_reset(chain);
03626 
03627         chain->magic = 0;
03628 }
03629 
03630 /* XXXMUKS:
03631  *
03632  * - worth removing inline as static functions are inlined automatically
03633  *   where suitable by modern compilers.
03634  * - bump the size of dns_rbt.nodecount to size_t.
03635  * - the dumpfile header also contains a nodecount that is unsigned
03636  *   int. If large files (> 2^32 nodes) are to be supported, the
03637  *   allocation for this field should be increased.
03638  */

Generated on Tue Apr 28 17:40:59 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha