Annotation of embedaddon/sudo/plugins/sudoers/redblack.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2004-2005, 2007, 2009-2011
! 3: * Todd C. Miller <Todd.Miller@courtesan.com>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: /*
! 19: * Adapted from the following code written by Emin Martinian:
! 20: * http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
! 21: *
! 22: * Copyright (c) 2001 Emin Martinian
! 23: *
! 24: * Redistribution and use in source and binary forms, with or without
! 25: * modification, are permitted provided that neither the name of Emin
! 26: * Martinian nor the names of any contributors are be used to endorse or
! 27: * promote products derived from this software without specific prior
! 28: * written permission.
! 29: *
! 30: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 31: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 32: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
! 33: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
! 34: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 35: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
! 36: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 37: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 38: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 39: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 40: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 41: */
! 42:
! 43: #include <config.h>
! 44:
! 45: #include <sys/types.h>
! 46: #include <sys/param.h>
! 47:
! 48: #include <stdio.h>
! 49: #ifdef STDC_HEADERS
! 50: # include <stdlib.h>
! 51: # include <stddef.h>
! 52: #else
! 53: # ifdef HAVE_STDLIB_H
! 54: # include <stdlib.h>
! 55: # endif
! 56: #endif /* STDC_HEADERS */
! 57:
! 58: #include "missing.h"
! 59: #include "alloc.h"
! 60: #include "redblack.h"
! 61:
! 62: static void rbrepair(struct rbtree *, struct rbnode *);
! 63: static void rotate_left(struct rbtree *, struct rbnode *);
! 64: static void rotate_right(struct rbtree *, struct rbnode *);
! 65: static void _rbdestroy(struct rbtree *, struct rbnode *, void (*)(void *));
! 66:
! 67: /*
! 68: * Red-Black tree, see http://en.wikipedia.org/wiki/Red-black_tree
! 69: *
! 70: * A red-black tree is a binary search tree where each node has a color
! 71: * attribute, the value of which is either red or black. Essentially, it
! 72: * is just a convenient way to express a 2-3-4 binary search tree where
! 73: * the color indicates whether the node is part of a 3-node or a 4-node.
! 74: * In addition to the ordinary requirements imposed on binary search
! 75: * trees, we make the following additional requirements of any valid
! 76: * red-black tree:
! 77: * 1) Every node is either red or black.
! 78: * 2) The root is black.
! 79: * 3) All leaves are black.
! 80: * 4) Both children of each red node are black.
! 81: * 5) The paths from each leaf up to the root each contain the same
! 82: * number of black nodes.
! 83: */
! 84:
! 85: /*
! 86: * Create a red black tree struct using the specified compare routine.
! 87: * Allocates and returns the initialized (empty) tree.
! 88: */
! 89: struct rbtree *
! 90: rbcreate(int (*compar)(const void *, const void*))
! 91: {
! 92: struct rbtree *tree;
! 93:
! 94: tree = (struct rbtree *) emalloc(sizeof(*tree));
! 95: tree->compar = compar;
! 96:
! 97: /*
! 98: * We use a self-referencing sentinel node called nil to simplify the
! 99: * code by avoiding the need to check for NULL pointers.
! 100: */
! 101: tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
! 102: tree->nil.color = black;
! 103: tree->nil.data = NULL;
! 104:
! 105: /*
! 106: * Similarly, the fake root node keeps us from having to worry
! 107: * about splitting the root.
! 108: */
! 109: tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
! 110: tree->root.color = black;
! 111: tree->root.data = NULL;
! 112:
! 113: return tree;
! 114: }
! 115:
! 116: /*
! 117: * Perform a left rotation starting at node.
! 118: */
! 119: static void
! 120: rotate_left(struct rbtree *tree, struct rbnode *node)
! 121: {
! 122: struct rbnode *child;
! 123:
! 124: child = node->right;
! 125: node->right = child->left;
! 126:
! 127: if (child->left != rbnil(tree))
! 128: child->left->parent = node;
! 129: child->parent = node->parent;
! 130:
! 131: if (node == node->parent->left)
! 132: node->parent->left = child;
! 133: else
! 134: node->parent->right = child;
! 135: child->left = node;
! 136: node->parent = child;
! 137: }
! 138:
! 139: /*
! 140: * Perform a right rotation starting at node.
! 141: */
! 142: static void
! 143: rotate_right(struct rbtree *tree, struct rbnode *node)
! 144: {
! 145: struct rbnode *child;
! 146:
! 147: child = node->left;
! 148: node->left = child->right;
! 149:
! 150: if (child->right != rbnil(tree))
! 151: child->right->parent = node;
! 152: child->parent = node->parent;
! 153:
! 154: if (node == node->parent->left)
! 155: node->parent->left = child;
! 156: else
! 157: node->parent->right = child;
! 158: child->right = node;
! 159: node->parent = child;
! 160: }
! 161:
! 162: /*
! 163: * Insert data pointer into a redblack tree.
! 164: * Returns a NULL pointer on success. If a node matching "data"
! 165: * already exists, a pointer to the existant node is returned.
! 166: */
! 167: struct rbnode *
! 168: rbinsert(struct rbtree *tree, void *data)
! 169: {
! 170: struct rbnode *node = rbfirst(tree);
! 171: struct rbnode *parent = rbroot(tree);
! 172: int res;
! 173:
! 174: /* Find correct insertion point. */
! 175: while (node != rbnil(tree)) {
! 176: parent = node;
! 177: if ((res = tree->compar(data, node->data)) == 0)
! 178: return node;
! 179: node = res < 0 ? node->left : node->right;
! 180: }
! 181:
! 182: node = (struct rbnode *) emalloc(sizeof(*node));
! 183: node->data = data;
! 184: node->left = node->right = rbnil(tree);
! 185: node->parent = parent;
! 186: if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0)
! 187: parent->left = node;
! 188: else
! 189: parent->right = node;
! 190: node->color = red;
! 191:
! 192: /*
! 193: * If the parent node is black we are all set, if it is red we have
! 194: * the following possible cases to deal with. We iterate through
! 195: * the rest of the tree to make sure none of the required properties
! 196: * is violated.
! 197: *
! 198: * 1) The uncle is red. We repaint both the parent and uncle black
! 199: * and repaint the grandparent node red.
! 200: *
! 201: * 2) The uncle is black and the new node is the right child of its
! 202: * parent, and the parent in turn is the left child of its parent.
! 203: * We do a left rotation to switch the roles of the parent and
! 204: * child, relying on further iterations to fixup the old parent.
! 205: *
! 206: * 3) The uncle is black and the new node is the left child of its
! 207: * parent, and the parent in turn is the left child of its parent.
! 208: * We switch the colors of the parent and grandparent and perform
! 209: * a right rotation around the grandparent. This makes the former
! 210: * parent the parent of the new node and the former grandparent.
! 211: *
! 212: * Note that because we use a sentinel for the root node we never
! 213: * need to worry about replacing the root.
! 214: */
! 215: while (node->parent->color == red) {
! 216: struct rbnode *uncle;
! 217: if (node->parent == node->parent->parent->left) {
! 218: uncle = node->parent->parent->right;
! 219: if (uncle->color == red) {
! 220: node->parent->color = black;
! 221: uncle->color = black;
! 222: node->parent->parent->color = red;
! 223: node = node->parent->parent;
! 224: } else /* if (uncle->color == black) */ {
! 225: if (node == node->parent->right) {
! 226: node = node->parent;
! 227: rotate_left(tree, node);
! 228: }
! 229: node->parent->color = black;
! 230: node->parent->parent->color = red;
! 231: rotate_right(tree, node->parent->parent);
! 232: }
! 233: } else { /* if (node->parent == node->parent->parent->right) */
! 234: uncle = node->parent->parent->left;
! 235: if (uncle->color == red) {
! 236: node->parent->color = black;
! 237: uncle->color = black;
! 238: node->parent->parent->color = red;
! 239: node = node->parent->parent;
! 240: } else /* if (uncle->color == black) */ {
! 241: if (node == node->parent->left) {
! 242: node = node->parent;
! 243: rotate_right(tree, node);
! 244: }
! 245: node->parent->color = black;
! 246: node->parent->parent->color = red;
! 247: rotate_left(tree, node->parent->parent);
! 248: }
! 249: }
! 250: }
! 251: rbfirst(tree)->color = black; /* first node is always black */
! 252: return NULL;
! 253: }
! 254:
! 255: /*
! 256: * Look for a node matching key in tree.
! 257: * Returns a pointer to the node if found, else NULL.
! 258: */
! 259: struct rbnode *
! 260: rbfind(struct rbtree *tree, void *key)
! 261: {
! 262: struct rbnode *node = rbfirst(tree);
! 263: int res;
! 264:
! 265: while (node != rbnil(tree)) {
! 266: if ((res = tree->compar(key, node->data)) == 0)
! 267: return node;
! 268: node = res < 0 ? node->left : node->right;
! 269: }
! 270: return NULL;
! 271: }
! 272:
! 273: /*
! 274: * Call func() for each node, passing it the node data and a cookie;
! 275: * If func() returns non-zero for a node, the traversal stops and the
! 276: * error value is returned. Returns 0 on successful traversal.
! 277: */
! 278: int
! 279: rbapply_node(struct rbtree *tree, struct rbnode *node,
! 280: int (*func)(void *, void *), void *cookie, enum rbtraversal order)
! 281: {
! 282: int error;
! 283:
! 284: if (node != rbnil(tree)) {
! 285: if (order == preorder)
! 286: if ((error = func(node->data, cookie)) != 0)
! 287: return error;
! 288: if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0)
! 289: return error;
! 290: if (order == inorder)
! 291: if ((error = func(node->data, cookie)) != 0)
! 292: return error;
! 293: if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0)
! 294: return error;
! 295: if (order == postorder)
! 296: if ((error = func(node->data, cookie)) != 0)
! 297: return error;
! 298: }
! 299: return 0;
! 300: }
! 301:
! 302: /*
! 303: * Returns the successor of node, or nil if there is none.
! 304: */
! 305: static struct rbnode *
! 306: rbsuccessor(struct rbtree *tree, struct rbnode *node)
! 307: {
! 308: struct rbnode *succ;
! 309:
! 310: if ((succ = node->right) != rbnil(tree)) {
! 311: while (succ->left != rbnil(tree))
! 312: succ = succ->left;
! 313: } else {
! 314: /* No right child, move up until we find it or hit the root */
! 315: for (succ = node->parent; node == succ->right; succ = succ->parent)
! 316: node = succ;
! 317: if (succ == rbroot(tree))
! 318: succ = rbnil(tree);
! 319: }
! 320: return succ;
! 321: }
! 322:
! 323: /*
! 324: * Recursive portion of rbdestroy().
! 325: */
! 326: static void
! 327: _rbdestroy(struct rbtree *tree, struct rbnode *node, void (*destroy)(void *))
! 328: {
! 329: if (node != rbnil(tree)) {
! 330: _rbdestroy(tree, node->left, destroy);
! 331: _rbdestroy(tree, node->right, destroy);
! 332: if (destroy != NULL)
! 333: destroy(node->data);
! 334: efree(node);
! 335: }
! 336: }
! 337:
! 338: /*
! 339: * Destroy the specified tree, calling the destructor destroy
! 340: * for each node and then freeing the tree itself.
! 341: */
! 342: void
! 343: rbdestroy(struct rbtree *tree, void (*destroy)(void *))
! 344: {
! 345: _rbdestroy(tree, rbfirst(tree), destroy);
! 346: efree(tree);
! 347: }
! 348:
! 349: /*
! 350: * Delete node 'z' from the tree and return its data pointer.
! 351: */
! 352: void *rbdelete(struct rbtree *tree, struct rbnode *z)
! 353: {
! 354: struct rbnode *x, *y;
! 355: void *data = z->data;
! 356:
! 357: if (z->left == rbnil(tree) || z->right == rbnil(tree))
! 358: y = z;
! 359: else
! 360: y = rbsuccessor(tree, z);
! 361: x = (y->left == rbnil(tree)) ? y->right : y->left;
! 362:
! 363: if ((x->parent = y->parent) == rbroot(tree)) {
! 364: rbfirst(tree) = x;
! 365: } else {
! 366: if (y == y->parent->left)
! 367: y->parent->left = x;
! 368: else
! 369: y->parent->right = x;
! 370: }
! 371: if (y->color == black)
! 372: rbrepair(tree, x);
! 373: if (y != z) {
! 374: y->left = z->left;
! 375: y->right = z->right;
! 376: y->parent = z->parent;
! 377: y->color = z->color;
! 378: z->left->parent = z->right->parent = y;
! 379: if (z == z->parent->left)
! 380: z->parent->left = y;
! 381: else
! 382: z->parent->right = y;
! 383: }
! 384: free(z);
! 385:
! 386: return data;
! 387: }
! 388:
! 389: /*
! 390: * Repair the tree after a node has been deleted by rotating and repainting
! 391: * colors to restore the 4 properties inherent in red-black trees.
! 392: */
! 393: static void
! 394: rbrepair(struct rbtree *tree, struct rbnode *node)
! 395: {
! 396: struct rbnode *sibling;
! 397:
! 398: while (node->color == black && node != rbroot(tree)) {
! 399: if (node == node->parent->left) {
! 400: sibling = node->parent->right;
! 401: if (sibling->color == red) {
! 402: sibling->color = black;
! 403: node->parent->color = red;
! 404: rotate_left(tree, node->parent);
! 405: sibling = node->parent->right;
! 406: }
! 407: if (sibling->right->color == black && sibling->left->color == black) {
! 408: sibling->color = red;
! 409: node = node->parent;
! 410: } else {
! 411: if (sibling->right->color == black) {
! 412: sibling->left->color = black;
! 413: sibling->color = red;
! 414: rotate_right(tree, sibling);
! 415: sibling = node->parent->right;
! 416: }
! 417: sibling->color = node->parent->color;
! 418: node->parent->color = black;
! 419: sibling->right->color = black;
! 420: rotate_left(tree, node->parent);
! 421: node = rbroot(tree); /* exit loop */
! 422: }
! 423: } else { /* if (node == node->parent->right) */
! 424: sibling = node->parent->left;
! 425: if (sibling->color == red) {
! 426: sibling->color = black;
! 427: node->parent->color = red;
! 428: rotate_right(tree, node->parent);
! 429: sibling = node->parent->left;
! 430: }
! 431: if (sibling->right->color == black && sibling->left->color == black) {
! 432: sibling->color = red;
! 433: node = node->parent;
! 434: } else {
! 435: if (sibling->left->color == black) {
! 436: sibling->right->color = black;
! 437: sibling->color = red;
! 438: rotate_left(tree, sibling);
! 439: sibling = node->parent->left;
! 440: }
! 441: sibling->color = node->parent->color;
! 442: node->parent->color = black;
! 443: sibling->left->color = black;
! 444: rotate_right(tree, node->parent);
! 445: node = rbroot(tree); /* exit loop */
! 446: }
! 447: }
! 448: }
! 449: node->color = black;
! 450: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>