diff options
Diffstat (limited to 'notes.c')
-rw-r--r-- | notes.c | 224 |
1 files changed, 104 insertions, 120 deletions
@@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "notes.h" +#include "object-store.h" #include "blob.h" #include "tree.h" #include "utf8.h" @@ -64,7 +65,7 @@ struct non_note { #define CLR_PTR_TYPE(ptr) ((void *) ((uintptr_t) (ptr) & ~3)) #define SET_PTR_TYPE(ptr, type) ((void *) ((uintptr_t) (ptr) | (type))) -#define GET_NIBBLE(n, sha1) (((sha1[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f) +#define GET_NIBBLE(n, sha1) ((((sha1)[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f) #define KEY_INDEX (GIT_SHA1_RAWSZ - 1) #define FANOUT_PATH_SEPARATORS ((GIT_SHA1_HEXSZ / 2) - 1) @@ -146,7 +147,7 @@ static struct leaf_node *note_tree_find(struct notes_tree *t, void **p = note_tree_search(t, &tree, &n, key_sha1); if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) { struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p); - if (!hashcmp(key_sha1, l->key_oid.hash)) + if (hasheq(key_sha1, l->key_oid.hash)) return l; } return NULL; @@ -205,7 +206,7 @@ static void note_tree_remove(struct notes_tree *t, if (GET_PTR_TYPE(*p) != PTR_TYPE_NOTE) return; /* type mismatch, nothing to remove */ l = (struct leaf_node *) CLR_PTR_TYPE(*p); - if (oidcmp(&l->key_oid, &entry->key_oid)) + if (!oideq(&l->key_oid, &entry->key_oid)) return; /* key mismatch, nothing to remove */ /* we have found a matching entry */ @@ -265,13 +266,13 @@ static int note_tree_insert(struct notes_tree *t, struct int_node *tree, case PTR_TYPE_NOTE: switch (type) { case PTR_TYPE_NOTE: - if (!oidcmp(&l->key_oid, &entry->key_oid)) { + if (oideq(&l->key_oid, &entry->key_oid)) { /* skip concatenation if l == entry */ - if (!oidcmp(&l->val_oid, &entry->val_oid)) + if (oideq(&l->val_oid, &entry->val_oid)) return 0; - ret = combine_notes(l->val_oid.hash, - entry->val_oid.hash); + 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); @@ -334,34 +335,6 @@ static void note_tree_free(struct int_node *tree) } } -/* - * Convert a partial SHA1 hex string to the corresponding partial SHA1 value. - * - hex - Partial SHA1 segment in ASCII hex format - * - hex_len - Length of above segment. Must be multiple of 2 between 0 and 40 - * - sha1 - Partial SHA1 value is written here - * - sha1_len - Max #bytes to store in sha1, Must be >= hex_len / 2, and < 20 - * Returns -1 on error (invalid arguments or invalid SHA1 (not in hex format)). - * Otherwise, returns number of bytes written to sha1 (i.e. hex_len / 2). - * Pads sha1 with NULs up to sha1_len (not included in returned length). - */ -static int get_oid_hex_segment(const char *hex, unsigned int hex_len, - unsigned char *oid, unsigned int oid_len) -{ - unsigned int i, len = hex_len >> 1; - if (hex_len % 2 != 0 || len > oid_len) - return -1; - for (i = 0; i < len; i++) { - unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]); - if (val & ~0xff) - return -1; - *oid++ = val; - hex += 2; - } - for (; i < oid_len; i++) - *oid++ = 0; - return len; -} - static int non_note_cmp(const struct non_note *a, const struct non_note *b) { return strcmp(a->path, b->path); @@ -417,80 +390,90 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree, struct int_node *node, unsigned int n) { struct object_id object_oid; - unsigned int prefix_len; + size_t prefix_len; void *buf; struct tree_desc desc; struct name_entry entry; - int len, path_len; - unsigned char type; - struct leaf_node *l; - buf = fill_tree_descriptor(&desc, subtree->val_oid.hash); + buf = fill_tree_descriptor(&desc, &subtree->val_oid); if (!buf) die("Could not read %s for notes-index", oid_to_hex(&subtree->val_oid)); prefix_len = subtree->key_oid.hash[KEY_INDEX]; - assert(prefix_len * 2 >= n); + if (prefix_len >= GIT_SHA1_RAWSZ) + BUG("prefix_len (%"PRIuMAX") is out of range", (uintmax_t)prefix_len); + if (prefix_len * 2 < n) + BUG("prefix_len (%"PRIuMAX") is too small", (uintmax_t)prefix_len); memcpy(object_oid.hash, subtree->key_oid.hash, prefix_len); while (tree_entry(&desc, &entry)) { - path_len = strlen(entry.path); - len = get_oid_hex_segment(entry.path, path_len, - object_oid.hash + prefix_len, GIT_SHA1_RAWSZ - prefix_len); - if (len < 0) - goto handle_non_note; /* entry.path is not a SHA1 */ - len += prefix_len; + unsigned char type; + struct leaf_node *l; + size_t path_len = strlen(entry.path); + + if (path_len == 2 * (GIT_SHA1_RAWSZ - prefix_len)) { + /* This is potentially the remainder of the SHA-1 */ + + if (!S_ISREG(entry.mode)) + /* notes must be blobs */ + goto handle_non_note; + + if (hex_to_bytes(object_oid.hash + prefix_len, entry.path, + GIT_SHA1_RAWSZ - prefix_len)) + goto handle_non_note; /* entry.path is not a SHA1 */ - /* - * If object SHA1 is complete (len == 20), assume note object - * If object SHA1 is incomplete (len < 20), and current - * component consists of 2 hex chars, assume note subtree - */ - if (len <= GIT_SHA1_RAWSZ) { type = PTR_TYPE_NOTE; - l = (struct leaf_node *) - xcalloc(1, sizeof(struct leaf_node)); - oidcpy(&l->key_oid, &object_oid); - oidcpy(&l->val_oid, entry.oid); - if (len < GIT_SHA1_RAWSZ) { - if (!S_ISDIR(entry.mode) || path_len != 2) - goto handle_non_note; /* not subtree */ - l->key_oid.hash[KEY_INDEX] = (unsigned char) len; - type = PTR_TYPE_SUBTREE; - } - if (note_tree_insert(t, node, n, l, type, - combine_notes_concatenate)) - die("Failed to load %s %s into notes tree " - "from %s", - type == PTR_TYPE_NOTE ? "note" : "subtree", - oid_to_hex(&l->key_oid), t->ref); + } else if (path_len == 2) { + /* This is potentially an internal node */ + size_t len = prefix_len; + + if (!S_ISDIR(entry.mode)) + /* internal nodes must be trees */ + goto handle_non_note; + + if (hex_to_bytes(object_oid.hash + len++, entry.path, 1)) + goto handle_non_note; /* entry.path is not a SHA1 */ + + /* + * Pad the rest of the SHA-1 with zeros, + * except for the last byte, where we write + * the length: + */ + memset(object_oid.hash + len, 0, GIT_SHA1_RAWSZ - len - 1); + object_oid.hash[KEY_INDEX] = (unsigned char)len; + + type = PTR_TYPE_SUBTREE; + } else { + /* This can't be part of a note */ + goto handle_non_note; } + + l = xcalloc(1, sizeof(*l)); + oidcpy(&l->key_oid, &object_oid); + oidcpy(&l->val_oid, entry.oid); + if (note_tree_insert(t, node, n, l, type, + combine_notes_concatenate)) + die("Failed to load %s %s into notes tree " + "from %s", + type == PTR_TYPE_NOTE ? "note" : "subtree", + oid_to_hex(&l->key_oid), t->ref); + continue; handle_non_note: /* - * Determine full path for this non-note entry: - * The filename is already found in entry.path, but the - * directory part of the path must be deduced from the subtree - * containing this entry. We assume here that the overall notes - * tree follows a strict byte-based progressive fanout - * structure (i.e. using 2/38, 2/2/36, etc. fanouts, and not - * e.g. 4/36 fanout). This means that if a non-note is found at - * path "dead/beef", the following code will register it as - * being found on "de/ad/beef". - * On the other hand, if you use such non-obvious non-note - * paths in the middle of a notes tree, you deserve what's - * coming to you ;). Note that for non-notes that are not - * SHA1-like at the top level, there will be no problems. - * - * To conclude, it is strongly advised to make sure non-notes - * have at least one non-hex character in the top-level path - * component. + * Determine full path for this non-note entry. The + * filename is already found in entry.path, but the + * directory part of the path must be deduced from the + * subtree containing this entry based on our + * knowledge that the overall notes tree follows a + * strict byte-based progressive fanout structure + * (i.e. using 2/38, 2/2/36, etc. fanouts). */ { struct strbuf non_note_path = STRBUF_INIT; const char *q = oid_to_hex(&subtree->key_oid); - int i; + size_t i; for (i = 0; i < prefix_len; i++) { strbuf_addch(&non_note_path, *q++); strbuf_addch(&non_note_path, *q++); @@ -685,7 +668,7 @@ static int tree_write_stack_finish_subtree(struct tree_write_stack *tws) ret = tree_write_stack_finish_subtree(n); if (ret) return ret; - ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s.hash); + ret = write_object_file(n->buf.buf, n->buf.len, tree_type, &s); if (ret) return ret; strbuf_release(&n->buf); @@ -804,8 +787,8 @@ static int prune_notes_helper(const struct object_id *object_oid, return 0; } -int combine_notes_concatenate(unsigned char *cur_sha1, - const unsigned char *new_sha1) +int combine_notes_concatenate(struct object_id *cur_oid, + const struct object_id *new_oid) { char *cur_msg = NULL, *new_msg = NULL, *buf; unsigned long cur_len, new_len, buf_len; @@ -813,18 +796,18 @@ int combine_notes_concatenate(unsigned char *cur_sha1, int ret; /* read in both note blob objects */ - if (!is_null_sha1(new_sha1)) - new_msg = read_sha1_file(new_sha1, &new_type, &new_len); + if (!is_null_oid(new_oid)) + new_msg = read_object_file(new_oid, &new_type, &new_len); if (!new_msg || !new_len || new_type != OBJ_BLOB) { free(new_msg); return 0; } - if (!is_null_sha1(cur_sha1)) - cur_msg = read_sha1_file(cur_sha1, &cur_type, &cur_len); + if (!is_null_oid(cur_oid)) + cur_msg = read_object_file(cur_oid, &cur_type, &cur_len); if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) { free(cur_msg); free(new_msg); - hashcpy(cur_sha1, new_sha1); + oidcpy(cur_oid, new_oid); return 0; } @@ -843,20 +826,20 @@ int combine_notes_concatenate(unsigned char *cur_sha1, free(new_msg); /* create a new blob object from buf */ - ret = write_sha1_file(buf, buf_len, blob_type, cur_sha1); + ret = write_object_file(buf, buf_len, blob_type, cur_oid); free(buf); return ret; } -int combine_notes_overwrite(unsigned char *cur_sha1, - const unsigned char *new_sha1) +int combine_notes_overwrite(struct object_id *cur_oid, + const struct object_id *new_oid) { - hashcpy(cur_sha1, new_sha1); + oidcpy(cur_oid, new_oid); return 0; } -int combine_notes_ignore(unsigned char *cur_sha1, - const unsigned char *new_sha1) +int combine_notes_ignore(struct object_id *cur_oid, + const struct object_id *new_oid) { return 0; } @@ -866,17 +849,17 @@ int combine_notes_ignore(unsigned char *cur_sha1, * newlines removed. */ static int string_list_add_note_lines(struct string_list *list, - const unsigned char *sha1) + const struct object_id *oid) { char *data; unsigned long len; enum object_type t; - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return 0; /* read_sha1_file NUL-terminates */ - data = read_sha1_file(sha1, &t, &len); + data = read_object_file(oid, &t, &len); if (t != OBJ_BLOB || !data || !len) { free(data); return t != OBJ_BLOB || !data; @@ -902,17 +885,17 @@ static int string_list_join_lines_helper(struct string_list_item *item, return 0; } -int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, - const unsigned char *new_sha1) +int combine_notes_cat_sort_uniq(struct object_id *cur_oid, + const struct object_id *new_oid) { struct string_list sort_uniq_list = STRING_LIST_INIT_DUP; struct strbuf buf = STRBUF_INIT; int ret = 1; /* read both note blob objects into unique_lines */ - if (string_list_add_note_lines(&sort_uniq_list, cur_sha1)) + if (string_list_add_note_lines(&sort_uniq_list, cur_oid)) goto out; - if (string_list_add_note_lines(&sort_uniq_list, new_sha1)) + if (string_list_add_note_lines(&sort_uniq_list, new_oid)) goto out; string_list_remove_empty_items(&sort_uniq_list, 0); string_list_sort(&sort_uniq_list); @@ -923,7 +906,7 @@ int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, string_list_join_lines_helper, &buf)) goto out; - ret = write_sha1_file(buf.buf, buf.len, blob_type, cur_sha1); + ret = write_object_file(buf.buf, buf.len, blob_type, cur_oid); out: strbuf_release(&buf); @@ -1026,11 +1009,11 @@ void init_notes(struct notes_tree *t, const char *notes_ref, t->dirty = 0; if (flags & NOTES_INIT_EMPTY || !notes_ref || - get_sha1_treeish(notes_ref, object_oid.hash)) + get_oid_treeish(notes_ref, &object_oid)) return; - if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_oid.hash)) + 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.hash, "", oid.hash, &mode)) + 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)); @@ -1141,11 +1124,12 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn, return for_each_note_helper(t, t->root, 0, 0, flags, fn, cb_data); } -int write_notes_tree(struct notes_tree *t, unsigned char *result) +int write_notes_tree(struct notes_tree *t, struct object_id *result) { struct tree_write_stack root; struct write_each_note_data cb_data; int ret; + int flags; if (!t) t = &default_notes_tree; @@ -1159,12 +1143,12 @@ int write_notes_tree(struct notes_tree *t, unsigned char *result) cb_data.next_non_note = t->first_non_note; /* Write tree objects representing current notes tree */ - ret = for_each_note(t, FOR_EACH_NOTE_DONT_UNPACK_SUBTREES | - FOR_EACH_NOTE_YIELD_SUBTREES, - write_each_note, &cb_data) || - write_each_non_note_until(NULL, &cb_data) || - tree_write_stack_finish_subtree(&root) || - write_sha1_file(root.buf.buf, root.buf.len, tree_type, result); + flags = FOR_EACH_NOTE_DONT_UNPACK_SUBTREES | + FOR_EACH_NOTE_YIELD_SUBTREES; + ret = for_each_note(t, flags, write_each_note, &cb_data) || + write_each_non_note_until(NULL, &cb_data) || + tree_write_stack_finish_subtree(&root) || + write_object_file(root.buf.buf, root.buf.len, tree_type, result); strbuf_release(&root.buf); return ret; } @@ -1234,7 +1218,7 @@ static void format_note(struct notes_tree *t, const struct object_id *object_oid if (!oid) return; - if (!(msg = read_sha1_file(oid->hash, &type, &msglen)) || type != OBJ_BLOB) { + if (!(msg = read_object_file(oid, &type, &msglen)) || type != OBJ_BLOB) { free(msg); return; } |