void init_notes(struct notes_tree *t, const char *notes_ref, combine_notes_fn combine_notes, int flags) { struct object_id oid, object_oid; unsigned mode; struct leaf_node root_tree; if (!t) t = &default_notes_tree; assert(!t->initialized); if (!notes_ref) notes_ref = default_notes_ref(); if (!combine_notes) combine_notes = combine_notes_concatenate; t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node)); t->first_non_note = NULL; t->prev_non_note = NULL; t->ref = xstrdup_or_null(notes_ref); t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL; t->combine_notes = combine_notes; t->initialized = 1; t->dirty = 0; if (flags & NOTES_INIT_EMPTY || !notes_ref || get_oid_treeish(notes_ref, &object_oid)) return; if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid)) die("Cannot use notes ref %s", notes_ref); if (get_tree_entry(&object_oid, "", &oid, &mode)) die("Failed to read notes tree referenced by %s (%s)", notes_ref, oid_to_hex(&object_oid)); oidclr(&root_tree.key_oid); oidcpy(&root_tree.val_oid, &oid); load_subtree(t, &root_tree, t->root, 0); }
void init_notes(struct notes_tree *t, const char *notes_ref, combine_notes_fn combine_notes, int flags) { unsigned char sha1[20], object_sha1[20]; unsigned mode; struct leaf_node root_tree; if (!t) t = &default_notes_tree; assert(!t->initialized); if (!notes_ref) notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT); if (!notes_ref) notes_ref = notes_ref_name; /* value of core.notesRef config */ if (!notes_ref) notes_ref = GIT_NOTES_DEFAULT_REF; if (!combine_notes) combine_notes = combine_notes_concatenate; t->root = (struct int_node *) xcalloc(sizeof(struct int_node), 1); t->first_non_note = NULL; t->prev_non_note = NULL; t->ref = notes_ref ? xstrdup(notes_ref) : NULL; t->combine_notes = combine_notes; t->initialized = 1; if (flags & NOTES_INIT_EMPTY || !notes_ref || read_ref(notes_ref, object_sha1)) return; if (get_tree_entry(object_sha1, "", sha1, &mode)) die("Failed to read notes tree referenced by %s (%s)", notes_ref, object_sha1); hashclr(root_tree.key_sha1); hashcpy(root_tree.val_sha1, sha1); load_subtree(t, &root_tree, t->root, 0); }
void init_notes(struct notes_tree *t, const char *notes_ref, combine_notes_fn combine_notes, int flags) { unsigned char sha1[20], object_sha1[20]; unsigned mode; struct leaf_node root_tree; if (!t) t = &default_notes_tree; assert(!t->initialized); if (!notes_ref) notes_ref = default_notes_ref(); if (!combine_notes) combine_notes = combine_notes_concatenate; t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node)); t->first_non_note = NULL; t->prev_non_note = NULL; t->ref = xstrdup_or_null(notes_ref); t->combine_notes = combine_notes; t->initialized = 1; t->dirty = 0; if (flags & NOTES_INIT_EMPTY || !notes_ref || read_ref(notes_ref, object_sha1)) return; if (get_tree_entry(object_sha1, "", sha1, &mode)) die("Failed to read notes tree referenced by %s (%s)", notes_ref, sha1_to_hex(object_sha1)); hashclr(root_tree.key_sha1); hashcpy(root_tree.val_sha1, sha1); load_subtree(t, &root_tree, t->root, 0); }
static int for_each_note_helper(struct notes_tree *t, struct int_node *tree, unsigned char n, unsigned char fanout, int flags, each_note_fn fn, void *cb_data) { unsigned int i; void *p; int ret = 0; struct leaf_node *l; static char path[FANOUT_PATH_MAX]; fanout = determine_fanout(tree, n, fanout); for (i = 0; i < 16; i++) { redo: p = tree->a[i]; switch (GET_PTR_TYPE(p)) { case PTR_TYPE_INTERNAL: /* recurse into int_node */ ret = for_each_note_helper(t, CLR_PTR_TYPE(p), n + 1, fanout, flags, fn, cb_data); break; case PTR_TYPE_SUBTREE: l = (struct leaf_node *) CLR_PTR_TYPE(p); /* * Subtree entries in the note tree represent parts of * the note tree that have not yet been explored. There * is a direct relationship between subtree entries at * level 'n' in the tree, and the 'fanout' variable: * Subtree entries at level 'n <= 2 * fanout' should be * preserved, since they correspond exactly to a fanout * directory in the on-disk structure. However, subtree * entries at level 'n > 2 * fanout' should NOT be * preserved, but rather consolidated into the above * notes tree level. We achieve this by unconditionally * unpacking subtree entries that exist below the * threshold level at 'n = 2 * fanout'. */ if (n <= 2 * fanout && flags & FOR_EACH_NOTE_YIELD_SUBTREES) { /* invoke callback with subtree */ unsigned int path_len = l->key_oid.hash[KEY_INDEX] * 2 + fanout; assert(path_len < FANOUT_PATH_MAX - 1); construct_path_with_fanout(l->key_oid.hash, fanout, path); /* Create trailing slash, if needed */ if (path[path_len - 1] != '/') path[path_len++] = '/'; path[path_len] = '\0'; ret = fn(&l->key_oid, &l->val_oid, path, cb_data); } if (n > fanout * 2 || !(flags & FOR_EACH_NOTE_DONT_UNPACK_SUBTREES)) { /* unpack subtree and resume traversal */ tree->a[i] = NULL; load_subtree(t, l, tree, n); free(l); goto redo; } break; case PTR_TYPE_NOTE: l = (struct leaf_node *) CLR_PTR_TYPE(p); construct_path_with_fanout(l->key_oid.hash, fanout, path); ret = fn(&l->key_oid, &l->val_oid, path, cb_data); break; } if (ret) return ret; } return 0; }
/* * To insert a leaf_node: * Search to the tree location appropriate for the given leaf_node's key: * - If location is unused (NULL), store the tweaked pointer directly there * - If location holds a note entry that matches the note-to-be-inserted, then * combine the two notes (by calling the given combine_notes function). * - If location holds a note entry that matches the subtree-to-be-inserted, * then unpack the subtree-to-be-inserted into the location. * - If location holds a matching subtree entry, unpack the subtree at that * location, and restart the insert operation from that level. * - Else, create a new int_node, holding both the node-at-location and the * node-to-be-inserted, and store the new int_node into the location. */ static int note_tree_insert(struct notes_tree *t, struct int_node *tree, unsigned char n, struct leaf_node *entry, unsigned char type, combine_notes_fn combine_notes) { struct int_node *new_node; struct leaf_node *l; void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash); int ret = 0; assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */ l = (struct leaf_node *) CLR_PTR_TYPE(*p); switch (GET_PTR_TYPE(*p)) { case PTR_TYPE_NULL: assert(!*p); if (is_null_oid(&entry->val_oid)) free(entry); else *p = SET_PTR_TYPE(entry, type); return 0; case PTR_TYPE_NOTE: switch (type) { case PTR_TYPE_NOTE: if (oideq(&l->key_oid, &entry->key_oid)) { /* skip concatenation if l == entry */ if (oideq(&l->val_oid, &entry->val_oid)) return 0; ret = combine_notes(&l->val_oid, &entry->val_oid); if (!ret && is_null_oid(&l->val_oid)) note_tree_remove(t, tree, n, entry); free(entry); return ret; } break; case PTR_TYPE_SUBTREE: if (!SUBTREE_SHA1_PREFIXCMP(l->key_oid.hash, entry->key_oid.hash)) { /* unpack 'entry' */ load_subtree(t, entry, tree, n); free(entry); return 0; } break; } break; case PTR_TYPE_SUBTREE: if (!SUBTREE_SHA1_PREFIXCMP(entry->key_oid.hash, l->key_oid.hash)) { /* unpack 'l' and restart insert */ *p = NULL; load_subtree(t, l, tree, n); free(l); return note_tree_insert(t, tree, n, entry, type, combine_notes); } break; } /* non-matching leaf_node */ assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE || GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE); if (is_null_oid(&entry->val_oid)) { /* skip insertion of empty note */ free(entry); return 0; } new_node = (struct int_node *) xcalloc(1, sizeof(struct int_node)); ret = note_tree_insert(t, new_node, n + 1, l, GET_PTR_TYPE(*p), combine_notes); if (ret) return ret; *p = SET_PTR_TYPE(new_node, PTR_TYPE_INTERNAL); return note_tree_insert(t, new_node, n + 1, entry, type, combine_notes); }
int register_mib_range(const char *moduleName, struct variable *var, size_t varsize, size_t numvars, oid *mibloc, size_t mibloclen, int priority, int range_subid, oid range_ubound, struct snmp_session *ss) { struct subtree *subtree, *sub2; int res, i; struct register_parameters reg_parms; subtree = (struct subtree *) malloc(sizeof(struct subtree)); if ( subtree == NULL ) return MIB_REGISTRATION_FAILED; memset(subtree, 0, sizeof(struct subtree)); DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName)); DEBUGMSGOID(("register_mib", mibloc, mibloclen)); DEBUGMSG(("register_mib","\n")); /* * Create the new subtree node being registered */ memcpy(subtree->name, mibloc, mibloclen*sizeof(oid)); subtree->namelen = (u_char) mibloclen; memcpy(subtree->start, mibloc, mibloclen*sizeof(oid)); subtree->start_len = (u_char) mibloclen; memcpy(subtree->end, mibloc, mibloclen*sizeof(oid)); subtree->end[ mibloclen-1 ]++; /* XXX - or use 'variables' info ? */ subtree->end_len = (u_char) mibloclen; memcpy(subtree->label, moduleName, strlen(moduleName)+1); if ( var ) { subtree->variables = (struct variable *) malloc(varsize*numvars); memcpy(subtree->variables, var, numvars*varsize); subtree->variables_len = numvars; subtree->variables_width = varsize; } subtree->priority = priority; subtree->session = ss; res = load_subtree(subtree); /* * If registering a range, * use the first subtree as a template * for the rest of the range */ if (( res == MIB_REGISTERED_OK ) && ( range_subid != 0 )) { for ( i = mibloc[range_subid-1] +1 ; i < (int)range_ubound ; i++ ) { sub2 = (struct subtree *) malloc(sizeof(struct subtree)); if ( sub2 == NULL ) { unregister_mib_range( mibloc, mibloclen, priority, range_subid, range_ubound); return MIB_REGISTRATION_FAILED; } memcpy( sub2, subtree, sizeof(struct subtree)); sub2->start[range_subid-1] = i; sub2->end[ range_subid-1] = i; /* XXX - ???? */ res = load_subtree(sub2); if ( res != MIB_REGISTERED_OK ) { unregister_mib_range( mibloc, mibloclen, priority, range_subid, range_ubound); return MIB_REGISTRATION_FAILED; } } } reg_parms.name = mibloc; reg_parms.namelen = mibloclen; reg_parms.priority = priority; reg_parms.range_subid = range_subid; reg_parms.range_ubound = range_ubound; snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_REGISTER_OID, ®_parms); return res; }
int load_subtree( struct subtree *new_sub ) { struct subtree *tree1, *tree2, *new2; struct subtree *prev, *next; int res; if ( new_sub == NULL ) return MIB_REGISTERED_OK; /* Degenerate case */ /* * Find the subtree that contains the start of * the new subtree (if any)... */ tree1 = find_subtree( new_sub->start, new_sub->start_len, NULL ); /* * ...and the subtree that follows the new one * (NULL implies this is the final region covered) */ if ( tree1 == NULL ) tree2 = find_subtree_next( new_sub->start, new_sub->start_len, NULL ); else tree2 = tree1->next; /* * Handle new subtrees that start in virgin territory. */ if ( tree1 == NULL ) { new2 = NULL; /* Is there any overlap with later subtrees ? */ if ( tree2 && snmp_oid_compare( new_sub->end, new_sub->end_len, tree2->start, tree2->start_len ) > 0 ) new2 = split_subtree( new_sub, tree2->start, tree2->start_len ); /* * Link the new subtree (less any overlapping region) * with the list of existing registrations */ if ( tree2 ) { new_sub->prev = tree2->prev; tree2->prev = new_sub; } else new_sub->prev = find_subtree_previous( new_sub->start, new_sub->start_len, NULL ); if ( new_sub->prev ) new_sub->prev->next = new_sub; else subtrees = new_sub; new_sub->next = tree2; /* * If there was any overlap, * recurse to merge in the overlapping region * (including anything that may follow the overlap) */ if ( new2 ) return load_subtree( new2 ); } else { /* * If the new subtree starts *within* an existing registration * (rather than at the same point as it), then split the * existing subtree at this point. */ if ( snmp_oid_compare( new_sub->start, new_sub->start_len, tree1->start, tree1->start_len) != 0 ) tree1 = split_subtree( tree1, new_sub->start, new_sub->start_len); if ( tree1 == NULL ) return MIB_REGISTRATION_FAILED; /* Now consider the end of this existing subtree: * If it matches the new subtree precisely, * simply merge the new one into the list of children * If it includes the whole of the new subtree, * split it at the appropriate point, and merge again * * If the new subtree extends beyond this existing region, * split it, and recurse to merge the two parts. */ switch ( snmp_oid_compare( new_sub->end, new_sub->end_len, tree1->end, tree1->end_len)) { case -1: /* Existing subtree contains new one */ (void) split_subtree( tree1, new_sub->end, new_sub->end_len); /* Fall Through */ case 0: /* The two trees match precisely */ /* * Note: This is the only point where the original * registration OID ("name") is used */ prev = NULL; next = tree1; while ( next && next->namelen > new_sub->namelen ) { prev = next; next = next->children; } while ( next && next->namelen == new_sub->namelen && next->priority < new_sub->priority ) { prev = next; next = next->children; } if ( next && next->namelen == new_sub->namelen && next->priority == new_sub->priority ) return MIB_DUPLICATE_REGISTRATION; if ( prev ) { new_sub->children = next; prev->children = new_sub; new_sub->prev = prev->prev; new_sub->next = prev->next; } else { new_sub->children = next; new_sub->prev = next->prev; new_sub->next = next->next; for ( next = new_sub->next ; next != NULL ; next = next->children ) next->prev = new_sub; for ( prev = new_sub->prev ; prev != NULL ; prev = prev->children ) prev->next = new_sub; } break; case 1: /* New subtree contains the existing one */ new2 = split_subtree( new_sub, tree1->end, tree1->end_len); res = load_subtree( new_sub ); if ( res != MIB_REGISTERED_OK ) return res; return load_subtree( new2 ); } } return 0; }
/* * To insert a leaf_node: * Search to the tree location appropriate for the given leaf_node's key: * - If location is unused (NULL), store the tweaked pointer directly there * - If location holds a note entry that matches the note-to-be-inserted, then * combine the two notes (by calling the given combine_notes function). * - If location holds a note entry that matches the subtree-to-be-inserted, * then unpack the subtree-to-be-inserted into the location. * - If location holds a matching subtree entry, unpack the subtree at that * location, and restart the insert operation from that level. * - Else, create a new int_node, holding both the node-at-location and the * node-to-be-inserted, and store the new int_node into the location. */ static void note_tree_insert(struct notes_tree *t, struct int_node *tree, unsigned char n, struct leaf_node *entry, unsigned char type, combine_notes_fn combine_notes) { struct int_node *new_node; struct leaf_node *l; void **p = note_tree_search(t, &tree, &n, entry->key_sha1); assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */ l = (struct leaf_node *) CLR_PTR_TYPE(*p); switch (GET_PTR_TYPE(*p)) { case PTR_TYPE_NULL: assert(!*p); *p = SET_PTR_TYPE(entry, type); return; case PTR_TYPE_NOTE: switch (type) { case PTR_TYPE_NOTE: if (!hashcmp(l->key_sha1, entry->key_sha1)) { /* skip concatenation if l == entry */ if (!hashcmp(l->val_sha1, entry->val_sha1)) return; if (combine_notes(l->val_sha1, entry->val_sha1)) die("failed to combine notes %s and %s" " for object %s", sha1_to_hex(l->val_sha1), sha1_to_hex(entry->val_sha1), sha1_to_hex(l->key_sha1)); free(entry); return; } break; case PTR_TYPE_SUBTREE: if (!SUBTREE_SHA1_PREFIXCMP(l->key_sha1, entry->key_sha1)) { /* unpack 'entry' */ load_subtree(t, entry, tree, n); free(entry); return; } break; } break; case PTR_TYPE_SUBTREE: if (!SUBTREE_SHA1_PREFIXCMP(entry->key_sha1, l->key_sha1)) { /* unpack 'l' and restart insert */ *p = NULL; load_subtree(t, l, tree, n); free(l); note_tree_insert(t, tree, n, entry, type, combine_notes); return; } break; } /* non-matching leaf_node */ assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE || GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE); new_node = (struct int_node *) xcalloc(sizeof(struct int_node), 1); note_tree_insert(t, new_node, n + 1, l, GET_PTR_TYPE(*p), combine_notes); *p = SET_PTR_TYPE(new_node, PTR_TYPE_INTERNAL); note_tree_insert(t, new_node, n + 1, entry, type, combine_notes); }