/* Knuth step T5, the insert. */ static struct ts_entry * tsearch_insert_k(const void *key,int kc, struct ts_entry *p) { struct ts_entry *q = allocate_ts_entry(key); if (!q) { /* out of memory */ return NULL; } setlink(p,kc,q); /* Non-NULL means inserted. */ return q; }
/** * copy a link, actually we recreate the link and only copy its stat() data. */ int copy_link(struct cow *cow) { int len; char link[PATHLEN_MAX]; if ((len = readlink(cow->from_path, link, sizeof(link)-1)) == -1) { syslog(LOG_WARNING, "readlink: %s", cow->from_path); return (1); } if (symlink(cow->from_path, cow->to_path)) { syslog(LOG_WARNING, "symlink: %s", link); return (1); } return setlink(cow->to_path, cow->stat); }
int copy_link(FTSENT *p, int exists) { int len; char link[MAXPATHLEN]; if ((len = readlink(p->fts_path, link, sizeof(link)-1)) == -1) { warn("readlink: %s", p->fts_path); return (1); } link[len] = '\0'; if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (symlink(link, to.p_path)) { warn("symlink: %s", link); return (1); } return (pflag ? setlink(p->fts_statp) : 0); }
static int copy_link(FTSENT *p, int exists) { int len; char linkname[PATH_MAX]; if ((len = readlink(p->fts_path, linkname, sizeof(linkname)-1)) == -1) { warn("readlink: %s", p->fts_path); return (1); } linkname[len] = '\0'; if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (symlink(linkname, to.p_path)) { warn("symlink: %s", linkname); return (1); } return (setlink(p->fts_statp)); }
/* Returns deleted node parent unless the head changed. Returns NULL if wanted node not found or the tree is now empty or the head node changed. Sets *did_delete if it found and deleted a node. Sets *tree_empty if there are no more user nodes present. */ static struct ts_entry * tdelete_inner(const void *key, struct ts_entry *head, int (*compar)(const void *, const void *), int *tree_empty, int *did_delete ) { struct ts_entry *p = 0; struct ts_entry *pp = 0; struct pkrecord * pkarray = 0; int depth = head->llink - (struct ts_entry *)0; unsigned k = 0; /* Allocate extra, head is on the stack we create here and the depth might increase. */ depth = depth + 4; pkarray = calloc(sizeof(struct pkrecord),depth); if(!pkarray) { /* Malloc fails, we could abort... */ return NULL; } k = 0; pkarray[k].pk=head; pkarray[k].ak=1; p = head->rlink; while(p) { int kc = 0; k++; kc = compar(key,p->keyptr); pkarray[k].pk = p; pkarray[k].ak = kc; if(!kc) { break; } p = getlink(p,kc); } if(!p) { /* Node to delete never found. */ free(pkarray); return NULL; } { struct ts_entry *p = 0; struct ts_entry *t = 0; struct ts_entry *r = 0; int pak = 0; int ppak = 0; p = pkarray[k].pk; pak = pkarray[k].ak; pp = pkarray[k-1].pk; ppak = pkarray[k-1].ak; /* Found a match. p to be deleted. */ t = p; *did_delete = 1; if(!t->rlink) { if(k == 1 && !t->llink) { *tree_empty = 1; /* upper level will fix up head node. */ free(t); free(pkarray); return NULL; } /* t->llink might be NULL. */ setlink(pp,ppak,t->llink); /* ASSERT: t->llink NULL or t->llink has no children, balance zero and balance of t->llink not changing. */ k--; /* Step D4. */ free(t); goto balance; } #ifdef IMPLEMENTD15 /* Step D1.5 */ if(!t->llink) { setlink(pp,ppak,t->rlink); /* we change the left link off ak */ k--; /* Step D4. */ free(t); goto balance; } #endif /* IMPLEMENTD15 */ /* Step D2 */ r = t->rlink; if (!r->llink) { /* We decrease the height of the right tree. */ r->llink = t->llink; setlink(pp,ppak,r); pkarray[k].pk = r; pkarray[k].ak = 1; /* The following essential line not mentioned in Knuth AFAICT. */ r->balance = t->balance; /* Step D4. */ free(t); goto balance; } /* Step D3, we rearrange the tree and pkarray so the balance step can work. step D2 is insufficient so not done. */ k = rearrange_tree_so_p_llink_null(pkarray,k, head,r, p,pak,pp,ppak); goto balance; } /* Now use pkarray decide if rebalancing needed and, if needed, to rebalance. k here matches l-1 in Knuth. */ balance: { unsigned k2 = k; /* We do not want a test in the for() itself. */ for( ; 1 ; k2--) { struct ts_entry *pk = 0; int ak = 0; int bk = 0; if (k2 == 0) { /* decreased in height */ head->llink--; goto cleanup; } pk = pkarray[k2].pk; if (!pk) { /* Nothing here to work with. Move up. */ continue; } ak = pkarray[k2].ak; bk = pk->balance; if(bk == ak) { pk->balance = 0; continue; } if(bk == 0) { pk->balance = -ak; goto cleanup; } /* ASSERT: bk == -ak. We will use bk == adel here (just below). */ /* Rebalancing required. Here we use (1) and (2) in 6.2.3 to adjust the nodes */ { /* Rebalance. We use s for what is called A in Knuth Case 1, Case 2 page 461. r For what is called B. So the link movement logic looks similar to the tsearch insert case.*/ struct ts_entry *r = 0; struct ts_entry *s = 0; struct ts_entry *pa = 0; int pak = 0; int adel = -ak; s = pk; r = getlink(s,adel); pa = pkarray[k2-1].pk; pak = pkarray[k2-1].ak; if(r->balance == adel) { /* case 1. */ setlink(s,adel,getlink(r,-adel)); setlink(r,-adel,s); /* A10 in tsearch. */ setlink(pa,pak,r); s->balance = 0; r->balance = 0; continue; } else if (r->balance == -adel) { /* case 2 */ /* x plays the role of p in step A9 */ struct ts_entry*x = getlink(r,-adel); setlink(r,-adel,getlink(x,adel)); setlink(x,adel,r); setlink(s,adel,getlink(x,-adel)); setlink(x,-adel,s); /* A10 in tsearch. */ setlink(pa,pak,x); if(x->balance == adel) { s->balance = -adel; r->balance = 0; } else if (x->balance == 0) { s->balance = 0; r->balance = 0; } else if (x->balance == -adel) { s->balance = 0; r->balance = adel; } x->balance = 0; continue; } else { /* r->balance == 0 case 3 we do a single rotation and we are done. */ setlink(s,adel,getlink(r,-adel)); setlink(r,-adel,s); setlink(pa,pak,r); r->balance = -adel; /*s->balance = r->balance = 0; */ goto cleanup; } } } } cleanup: free(pkarray); #ifdef DW_CHECK_CONSISTENCY dwarf_check_balance(head,1); #endif return pp; }
static unsigned rearrange_tree_so_p_llink_null( struct pkrecord * pkarray, unsigned k, struct ts_entry *head, struct ts_entry *r, struct ts_entry *p, UNUSEDARG int pak, struct ts_entry *pp, int ppak) { struct ts_entry *s = 0; unsigned k2 = 0; /* indexing pkarray */ int pbalance = p->balance; /* Step D3 */ /* Since we are going to modify the tree by movement of a node down the tree a ways, we need to build pkarray with the (not yet found) new next node, in pkarray[k], not p. The deletion will be of p, but by then p will be moved in the tree so it has a null left link. P's possibly-non-null right link */ k2 = k; k2++; r = p->rlink; pkarray[k2].pk = r; pkarray[k2].ak = -1; s = r->llink; /* Move down and left to get a null llink. */ while (s->llink) { k2++; r = s; s = r->llink; pkarray[k2].pk = r; pkarray[k2].ak = -1; } /* Now we move S up in place (in the tree) of the node P we will delete. and p replaces s. Finally winding up with a newly shaped balanced tree. */ { struct ts_entry *tmp = 0; int sbalance = s->balance; s->llink = p->llink; r->llink = p; p->llink = 0; tmp = p->rlink; p->rlink = s->rlink; s->rlink = tmp; setlink(pp,ppak,s); s->balance = pbalance; p->balance = sbalance; /* Now the tree is rearranged and still in balance. */ /* Replace the previous k position entry with S. We trace the right link off of the moved S node. */ pkarray[k].pk = s; pkarray[k].ak = 1; r->llink = p->rlink; /* Now p is out of the tree and we start the rebalance at r. pkarray Index k2. */ } /* Step D4 */ free(p); return k2; }
/* Algorithm A of Knuth 6.2.3, balanced tree. key is pointer to a user data area containing the key and possibly more. We could recurse on this routine, but instead we iterate (like Knuth does, but using for(;;) instead of go-to. */ static struct ts_entry * tsearch_inner( const void *key, struct ts_entry* head, int (*compar)(const void *, const void *), int*inserted, struct ts_entry **nullme, int * comparres) { /* t points to parent of p */ struct ts_entry *t = head; /* p moves down tree, p starts as root. */ struct ts_entry *p = head->rlink; /* s points where rebalancing may be needed. */ struct ts_entry *s = p; struct ts_entry *r = 0; struct ts_entry *q = 0; int a = 0; int kc = 0; for(;;) { /* A2. */ kc = compar(key,p->keyptr); if(kc) { /* A3 and A4 handled here. */ q = getlink(p,kc); if(!q) { /* Does step A5. */ q = tsearch_inner_do_insert(key,kc,inserted,p); if (!q) { /* Out of memory. */ return q; } break; /* to A5. */ } if(q->balance) { t = p; s = q; } p = q; continue; } /* K = KEY(P) in Knuth. */ /* kc == 0, we found the entry we search for. */ return p; } /* A5: work already done. */ /* A6: */ { /* Balance factors on nodes betwen S and Q need to be changed from zero to +-1 */ int kc2 = compar(key,s->keyptr); if (kc2 < 0) { a = -1; } else { a = 1; } r = p = getlink(s,a); while (p != q) { int kc3 = compar(key,p->keyptr); if(kc3 < 0) { p->balance = -1; p = p->llink; } else if (kc3 > 0) { p->balance = 1; p = p->rlink; } else { /* ASSERT: p == q */ break; } } } /* A7: */ { if(! s->balance) { /* Tree has grown higher. */ s->balance = a; /* Counting in pointers, not integers. Ugh. */ head->llink = head->llink + 1; return q; } if(s->balance == -a) { /* Tree is more balanced */ s->balance = 0; return q; } if (s->balance == a) { /* Rebalance. */ if(r->balance == a) { /* single rotation, step A8. */ p = r; setlink(s,a,getlink(r,-a)); setlink(r,-a,s); s->balance = 0; r->balance = 0; } else if (r->balance == -a) { /* double rotation, step A9. */ p = getlink(r,-a); setlink(r,-a,getlink(p,a)); setlink(p,a,r); setlink(s,a,getlink(p,-a)); setlink(p,-a,s); if(p->balance == a) { s->balance = -a; r->balance = 0; } else if (p->balance == 0) { s->balance = 0; r->balance = 0; } else if (p->balance == -a) { s->balance = 0; r->balance = a; } p->balance = 0; } else { fprintf(stderr,"Impossible balanced tree situation!\n"); /* Impossible. Cannot be here. */ exit(1); } } else { fprintf(stderr,"Impossible balanced tree situation!!\n"); /* Impossible. Cannot be here. */ exit(1); } } /* A10: */ if (s == t->rlink) { t->rlink = p; } else { t->llink = p; } #ifdef DW_CHECK_CONSISTENCY dwarf_check_balance(head,1); #endif return q; }