git
/
notes.c
1373 строки · 38.2 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "config.h"5#include "environment.h"6#include "hex.h"7#include "notes.h"8#include "object-name.h"9#include "object-store-ll.h"10#include "utf8.h"11#include "strbuf.h"12#include "tree-walk.h"13#include "string-list.h"14#include "refs.h"15
16/*
17* Use a non-balancing simple 16-tree structure with struct int_node as
18* internal nodes, and struct leaf_node as leaf nodes. Each int_node has a
19* 16-array of pointers to its children.
20* The bottom 2 bits of each pointer is used to identify the pointer type
21* - ptr & 3 == 0 - NULL pointer, assert(ptr == NULL)
22* - ptr & 3 == 1 - pointer to next internal node - cast to struct int_node *
23* - ptr & 3 == 2 - pointer to note entry - cast to struct leaf_node *
24* - ptr & 3 == 3 - pointer to subtree entry - cast to struct leaf_node *
25*
26* The root node is a statically allocated struct int_node.
27*/
28struct int_node {29void *a[16];30};31
32/*
33* Leaf nodes come in two variants, note entries and subtree entries,
34* distinguished by the LSb of the leaf node pointer (see above).
35* As a note entry, the key is the SHA1 of the referenced object, and the
36* value is the SHA1 of the note object.
37* As a subtree entry, the key is the prefix SHA1 (w/trailing NULs) of the
38* referenced object, using the last byte of the key to store the length of
39* the prefix. The value is the SHA1 of the tree object containing the notes
40* subtree.
41*/
42struct leaf_node {43struct object_id key_oid;44struct object_id val_oid;45};46
47/*
48* A notes tree may contain entries that are not notes, and that do not follow
49* the naming conventions of notes. There are typically none/few of these, but
50* we still need to keep track of them. Keep a simple linked list sorted alpha-
51* betically on the non-note path. The list is populated when parsing tree
52* objects in load_subtree(), and the non-notes are correctly written back into
53* the tree objects produced by write_notes_tree().
54*/
55struct non_note {56struct non_note *next; /* grounded (last->next == NULL) */57char *path;58unsigned int mode;59struct object_id oid;60};61
62#define PTR_TYPE_NULL 063#define PTR_TYPE_INTERNAL 164#define PTR_TYPE_NOTE 265#define PTR_TYPE_SUBTREE 366
67#define GET_PTR_TYPE(ptr) ((uintptr_t) (ptr) & 3)68#define CLR_PTR_TYPE(ptr) ((void *) ((uintptr_t) (ptr) & ~3))69#define SET_PTR_TYPE(ptr, type) ((void *) ((uintptr_t) (ptr) | (type)))70
71#define GET_NIBBLE(n, sha1) ((((sha1)[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f)72
73#define KEY_INDEX (the_hash_algo->rawsz - 1)74#define FANOUT_PATH_SEPARATORS (the_hash_algo->rawsz - 1)75#define FANOUT_PATH_SEPARATORS_MAX ((GIT_MAX_HEXSZ / 2) - 1)76#define SUBTREE_SHA1_PREFIXCMP(key_sha1, subtree_sha1) \77(memcmp(key_sha1, subtree_sha1, subtree_sha1[KEY_INDEX]))78
79struct notes_tree default_notes_tree;80
81static struct string_list display_notes_refs = STRING_LIST_INIT_NODUP;82static struct notes_tree **display_notes_trees;83
84static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,85struct int_node *node, unsigned int n);86
87/*
88* Search the tree until the appropriate location for the given key is found:
89* 1. Start at the root node, with n = 0
90* 2. If a[0] at the current level is a matching subtree entry, unpack that
91* subtree entry and remove it; restart search at the current level.
92* 3. Use the nth nibble of the key as an index into a:
93* - If a[n] is an int_node, recurse from #2 into that node and increment n
94* - If a matching subtree entry, unpack that subtree entry (and remove it);
95* restart search at the current level.
96* - Otherwise, we have found one of the following:
97* - a subtree entry which does not match the key
98* - a note entry which may or may not match the key
99* - an unused leaf node (NULL)
100* In any case, set *tree and *n, and return pointer to the tree location.
101*/
102static void **note_tree_search(struct notes_tree *t, struct int_node **tree,103unsigned char *n, const unsigned char *key_sha1)104{
105struct leaf_node *l;106unsigned char i;107void *p = (*tree)->a[0];108
109if (GET_PTR_TYPE(p) == PTR_TYPE_SUBTREE) {110l = (struct leaf_node *) CLR_PTR_TYPE(p);111if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_oid.hash)) {112/* unpack tree and resume search */113(*tree)->a[0] = NULL;114load_subtree(t, l, *tree, *n);115free(l);116return note_tree_search(t, tree, n, key_sha1);117}118}119
120i = GET_NIBBLE(*n, key_sha1);121p = (*tree)->a[i];122switch (GET_PTR_TYPE(p)) {123case PTR_TYPE_INTERNAL:124*tree = CLR_PTR_TYPE(p);125(*n)++;126return note_tree_search(t, tree, n, key_sha1);127case PTR_TYPE_SUBTREE:128l = (struct leaf_node *) CLR_PTR_TYPE(p);129if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_oid.hash)) {130/* unpack tree and resume search */131(*tree)->a[i] = NULL;132load_subtree(t, l, *tree, *n);133free(l);134return note_tree_search(t, tree, n, key_sha1);135}136/* fall through */137default:138return &((*tree)->a[i]);139}140}
141
142/*
143* To find a leaf_node:
144* Search to the tree location appropriate for the given key:
145* If a note entry with matching key, return the note entry, else return NULL.
146*/
147static struct leaf_node *note_tree_find(struct notes_tree *t,148struct int_node *tree, unsigned char n,149const unsigned char *key_sha1)150{
151void **p = note_tree_search(t, &tree, &n, key_sha1);152if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) {153struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p);154if (hasheq(key_sha1, l->key_oid.hash, the_repository->hash_algo))155return l;156}157return NULL;158}
159
160/*
161* How to consolidate an int_node:
162* If there are > 1 non-NULL entries, give up and return non-zero.
163* Otherwise replace the int_node at the given index in the given parent node
164* with the only NOTE entry (or a NULL entry if no entries) from the given
165* tree, and return 0.
166*/
167static int note_tree_consolidate(struct int_node *tree,168struct int_node *parent, unsigned char index)169{
170unsigned int i;171void *p = NULL;172
173assert(tree && parent);174assert(CLR_PTR_TYPE(parent->a[index]) == tree);175
176for (i = 0; i < 16; i++) {177if (GET_PTR_TYPE(tree->a[i]) != PTR_TYPE_NULL) {178if (p) /* more than one entry */179return -2;180p = tree->a[i];181}182}183
184if (p && (GET_PTR_TYPE(p) != PTR_TYPE_NOTE))185return -2;186/* replace tree with p in parent[index] */187parent->a[index] = p;188free(tree);189return 0;190}
191
192/*
193* To remove a leaf_node:
194* Search to the tree location appropriate for the given leaf_node's key:
195* - If location does not hold a matching entry, abort and do nothing.
196* - Copy the matching entry's value into the given entry.
197* - Replace the matching leaf_node with a NULL entry (and free the leaf_node).
198* - Consolidate int_nodes repeatedly, while walking up the tree towards root.
199*/
200static void note_tree_remove(struct notes_tree *t,201struct int_node *tree, unsigned char n,202struct leaf_node *entry)203{
204struct leaf_node *l;205struct int_node *parent_stack[GIT_MAX_RAWSZ];206unsigned char i, j;207void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash);208
209assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */210if (GET_PTR_TYPE(*p) != PTR_TYPE_NOTE)211return; /* type mismatch, nothing to remove */212l = (struct leaf_node *) CLR_PTR_TYPE(*p);213if (!oideq(&l->key_oid, &entry->key_oid))214return; /* key mismatch, nothing to remove */215
216/* we have found a matching entry */217oidcpy(&entry->val_oid, &l->val_oid);218free(l);219*p = SET_PTR_TYPE(NULL, PTR_TYPE_NULL);220
221/* consolidate this tree level, and parent levels, if possible */222if (!n)223return; /* cannot consolidate top level */224/* first, build stack of ancestors between root and current node */225parent_stack[0] = t->root;226for (i = 0; i < n; i++) {227j = GET_NIBBLE(i, entry->key_oid.hash);228parent_stack[i + 1] = CLR_PTR_TYPE(parent_stack[i]->a[j]);229}230assert(i == n && parent_stack[i] == tree);231/* next, unwind stack until note_tree_consolidate() is done */232while (i > 0 &&233!note_tree_consolidate(parent_stack[i], parent_stack[i - 1],234GET_NIBBLE(i - 1, entry->key_oid.hash)))235i--;236}
237
238/*
239* To insert a leaf_node:
240* Search to the tree location appropriate for the given leaf_node's key:
241* - If location is unused (NULL), store the tweaked pointer directly there
242* - If location holds a note entry that matches the note-to-be-inserted, then
243* combine the two notes (by calling the given combine_notes function).
244* - If location holds a note entry that matches the subtree-to-be-inserted,
245* then unpack the subtree-to-be-inserted into the location.
246* - If location holds a matching subtree entry, unpack the subtree at that
247* location, and restart the insert operation from that level.
248* - Else, create a new int_node, holding both the node-at-location and the
249* node-to-be-inserted, and store the new int_node into the location.
250*/
251static int note_tree_insert(struct notes_tree *t, struct int_node *tree,252unsigned char n, struct leaf_node *entry, unsigned char type,253combine_notes_fn combine_notes)254{
255struct int_node *new_node;256struct leaf_node *l;257void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash);258int ret = 0;259
260assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */261l = (struct leaf_node *) CLR_PTR_TYPE(*p);262switch (GET_PTR_TYPE(*p)) {263case PTR_TYPE_NULL:264assert(!*p);265if (is_null_oid(&entry->val_oid))266free(entry);267else268*p = SET_PTR_TYPE(entry, type);269return 0;270case PTR_TYPE_NOTE:271switch (type) {272case PTR_TYPE_NOTE:273if (oideq(&l->key_oid, &entry->key_oid)) {274/* skip concatenation if l == entry */275if (oideq(&l->val_oid, &entry->val_oid)) {276free(entry);277return 0;278}279
280ret = combine_notes(&l->val_oid,281&entry->val_oid);282if (!ret && is_null_oid(&l->val_oid))283note_tree_remove(t, tree, n, entry);284free(entry);285return ret;286}287break;288case PTR_TYPE_SUBTREE:289if (!SUBTREE_SHA1_PREFIXCMP(l->key_oid.hash,290entry->key_oid.hash)) {291/* unpack 'entry' */292load_subtree(t, entry, tree, n);293free(entry);294return 0;295}296break;297}298break;299case PTR_TYPE_SUBTREE:300if (!SUBTREE_SHA1_PREFIXCMP(entry->key_oid.hash, l->key_oid.hash)) {301/* unpack 'l' and restart insert */302*p = NULL;303load_subtree(t, l, tree, n);304free(l);305return note_tree_insert(t, tree, n, entry, type,306combine_notes);307}308break;309}310
311/* non-matching leaf_node */312assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE ||313GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE);314if (is_null_oid(&entry->val_oid)) { /* skip insertion of empty note */315free(entry);316return 0;317}318new_node = (struct int_node *) xcalloc(1, sizeof(struct int_node));319ret = note_tree_insert(t, new_node, n + 1, l, GET_PTR_TYPE(*p),320combine_notes);321if (ret)322return ret;323*p = SET_PTR_TYPE(new_node, PTR_TYPE_INTERNAL);324return note_tree_insert(t, new_node, n + 1, entry, type, combine_notes);325}
326
327/* Free the entire notes data contained in the given tree */
328static void note_tree_free(struct int_node *tree)329{
330unsigned int i;331for (i = 0; i < 16; i++) {332void *p = tree->a[i];333switch (GET_PTR_TYPE(p)) {334case PTR_TYPE_INTERNAL:335note_tree_free(CLR_PTR_TYPE(p));336/* fall through */337case PTR_TYPE_NOTE:338case PTR_TYPE_SUBTREE:339free(CLR_PTR_TYPE(p));340}341}342}
343
344static int non_note_cmp(const struct non_note *a, const struct non_note *b)345{
346return strcmp(a->path, b->path);347}
348
349/* note: takes ownership of path string */
350static void add_non_note(struct notes_tree *t, char *path,351unsigned int mode, const unsigned char *sha1)352{
353struct non_note *p = t->prev_non_note, *n;354n = (struct non_note *) xmalloc(sizeof(struct non_note));355n->next = NULL;356n->path = path;357n->mode = mode;358oidread(&n->oid, sha1, the_repository->hash_algo);359t->prev_non_note = n;360
361if (!t->first_non_note) {362t->first_non_note = n;363return;364}365
366if (non_note_cmp(p, n) < 0)367; /* do nothing */368else if (non_note_cmp(t->first_non_note, n) <= 0)369p = t->first_non_note;370else {371/* n sorts before t->first_non_note */372n->next = t->first_non_note;373t->first_non_note = n;374return;375}376
377/* n sorts equal or after p */378while (p->next && non_note_cmp(p->next, n) <= 0)379p = p->next;380
381if (non_note_cmp(p, n) == 0) { /* n ~= p; overwrite p with n */382assert(strcmp(p->path, n->path) == 0);383p->mode = n->mode;384oidcpy(&p->oid, &n->oid);385free(n);386t->prev_non_note = p;387return;388}389
390/* n sorts between p and p->next */391n->next = p->next;392p->next = n;393}
394
395static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,396struct int_node *node, unsigned int n)397{
398struct object_id object_oid;399size_t prefix_len;400void *buf;401struct tree_desc desc;402struct name_entry entry;403const unsigned hashsz = the_hash_algo->rawsz;404
405buf = fill_tree_descriptor(the_repository, &desc, &subtree->val_oid);406if (!buf)407die("Could not read %s for notes-index",408oid_to_hex(&subtree->val_oid));409
410prefix_len = subtree->key_oid.hash[KEY_INDEX];411if (prefix_len >= hashsz)412BUG("prefix_len (%"PRIuMAX") is out of range", (uintmax_t)prefix_len);413if (prefix_len * 2 < n)414BUG("prefix_len (%"PRIuMAX") is too small", (uintmax_t)prefix_len);415memcpy(object_oid.hash, subtree->key_oid.hash, prefix_len);416while (tree_entry(&desc, &entry)) {417unsigned char type;418struct leaf_node *l;419size_t path_len = strlen(entry.path);420
421if (path_len == 2 * (hashsz - prefix_len)) {422/* This is potentially the remainder of the SHA-1 */423
424if (!S_ISREG(entry.mode))425/* notes must be blobs */426goto handle_non_note;427
428if (hex_to_bytes(object_oid.hash + prefix_len, entry.path,429hashsz - prefix_len))430goto handle_non_note; /* entry.path is not a SHA1 */431
432memset(object_oid.hash + hashsz, 0, GIT_MAX_RAWSZ - hashsz);433
434type = PTR_TYPE_NOTE;435} else if (path_len == 2) {436/* This is potentially an internal node */437size_t len = prefix_len;438
439if (!S_ISDIR(entry.mode))440/* internal nodes must be trees */441goto handle_non_note;442
443if (hex_to_bytes(object_oid.hash + len++, entry.path, 1))444goto handle_non_note; /* entry.path is not a SHA1 */445
446/*447* Pad the rest of the SHA-1 with zeros,
448* except for the last byte, where we write
449* the length:
450*/
451memset(object_oid.hash + len, 0, hashsz - len - 1);452object_oid.hash[KEY_INDEX] = (unsigned char)len;453
454type = PTR_TYPE_SUBTREE;455} else {456/* This can't be part of a note */457goto handle_non_note;458}459
460CALLOC_ARRAY(l, 1);461oidcpy(&l->key_oid, &object_oid);462oidcpy(&l->val_oid, &entry.oid);463oid_set_algo(&l->key_oid, the_hash_algo);464oid_set_algo(&l->val_oid, the_hash_algo);465if (note_tree_insert(t, node, n, l, type,466combine_notes_concatenate))467die("Failed to load %s %s into notes tree "468"from %s",469type == PTR_TYPE_NOTE ? "note" : "subtree",470oid_to_hex(&object_oid), t->ref);471
472continue;473
474handle_non_note:475/*476* Determine full path for this non-note entry. The
477* filename is already found in entry.path, but the
478* directory part of the path must be deduced from the
479* subtree containing this entry based on our
480* knowledge that the overall notes tree follows a
481* strict byte-based progressive fanout structure
482* (i.e. using 2/38, 2/2/36, etc. fanouts).
483*/
484{485struct strbuf non_note_path = STRBUF_INIT;486const char *q = oid_to_hex(&subtree->key_oid);487size_t i;488for (i = 0; i < prefix_len; i++) {489strbuf_addch(&non_note_path, *q++);490strbuf_addch(&non_note_path, *q++);491strbuf_addch(&non_note_path, '/');492}493strbuf_addstr(&non_note_path, entry.path);494oid_set_algo(&entry.oid, the_hash_algo);495add_non_note(t, strbuf_detach(&non_note_path, NULL),496entry.mode, entry.oid.hash);497}498}499free(buf);500}
501
502/*
503* Determine optimal on-disk fanout for this part of the notes tree
504*
505* Given a (sub)tree and the level in the internal tree structure, determine
506* whether or not the given existing fanout should be expanded for this
507* (sub)tree.
508*
509* Values of the 'fanout' variable:
510* - 0: No fanout (all notes are stored directly in the root notes tree)
511* - 1: 2/38 fanout
512* - 2: 2/2/36 fanout
513* - 3: 2/2/2/34 fanout
514* etc.
515*/
516static unsigned char determine_fanout(struct int_node *tree, unsigned char n,517unsigned char fanout)518{
519/*520* The following is a simple heuristic that works well in practice:
521* For each even-numbered 16-tree level (remember that each on-disk
522* fanout level corresponds to _two_ 16-tree levels), peek at all 16
523* entries at that tree level. If all of them are either int_nodes or
524* subtree entries, then there are likely plenty of notes below this
525* level, so we return an incremented fanout.
526*/
527unsigned int i;528if ((n % 2) || (n > 2 * fanout))529return fanout;530for (i = 0; i < 16; i++) {531switch (GET_PTR_TYPE(tree->a[i])) {532case PTR_TYPE_SUBTREE:533case PTR_TYPE_INTERNAL:534continue;535default:536return fanout;537}538}539return fanout + 1;540}
541
542/* hex oid + '/' between each pair of hex digits + NUL */
543#define FANOUT_PATH_MAX GIT_MAX_HEXSZ + FANOUT_PATH_SEPARATORS_MAX + 1544
545static void construct_path_with_fanout(const unsigned char *hash,546unsigned char fanout, char *path)547{
548unsigned int i = 0, j = 0;549const char *hex_hash = hash_to_hex(hash);550assert(fanout < the_hash_algo->rawsz);551while (fanout) {552path[i++] = hex_hash[j++];553path[i++] = hex_hash[j++];554path[i++] = '/';555fanout--;556}557xsnprintf(path + i, FANOUT_PATH_MAX - i, "%s", hex_hash + j);558}
559
560static int for_each_note_helper(struct notes_tree *t, struct int_node *tree,561unsigned char n, unsigned char fanout, int flags,562each_note_fn fn, void *cb_data)563{
564unsigned int i;565void *p;566int ret = 0;567struct leaf_node *l;568static char path[FANOUT_PATH_MAX];569
570fanout = determine_fanout(tree, n, fanout);571for (i = 0; i < 16; i++) {572redo:573p = tree->a[i];574switch (GET_PTR_TYPE(p)) {575case PTR_TYPE_INTERNAL:576/* recurse into int_node */577ret = for_each_note_helper(t, CLR_PTR_TYPE(p), n + 1,578fanout, flags, fn, cb_data);579break;580case PTR_TYPE_SUBTREE:581l = (struct leaf_node *) CLR_PTR_TYPE(p);582/*583* Subtree entries in the note tree represent parts of
584* the note tree that have not yet been explored. There
585* is a direct relationship between subtree entries at
586* level 'n' in the tree, and the 'fanout' variable:
587* Subtree entries at level 'n < 2 * fanout' should be
588* preserved, since they correspond exactly to a fanout
589* directory in the on-disk structure. However, subtree
590* entries at level 'n >= 2 * fanout' should NOT be
591* preserved, but rather consolidated into the above
592* notes tree level. We achieve this by unconditionally
593* unpacking subtree entries that exist below the
594* threshold level at 'n = 2 * fanout'.
595*/
596if (n < 2 * fanout &&597flags & FOR_EACH_NOTE_YIELD_SUBTREES) {598/* invoke callback with subtree */599unsigned int path_len =600l->key_oid.hash[KEY_INDEX] * 2 + fanout;601assert(path_len < FANOUT_PATH_MAX - 1);602construct_path_with_fanout(l->key_oid.hash,603fanout,604path);605/* Create trailing slash, if needed */606if (path[path_len - 1] != '/')607path[path_len++] = '/';608path[path_len] = '\0';609ret = fn(&l->key_oid, &l->val_oid,610path,611cb_data);612}613if (n >= 2 * fanout ||614!(flags & FOR_EACH_NOTE_DONT_UNPACK_SUBTREES)) {615/* unpack subtree and resume traversal */616tree->a[i] = NULL;617load_subtree(t, l, tree, n);618free(l);619goto redo;620}621break;622case PTR_TYPE_NOTE:623l = (struct leaf_node *) CLR_PTR_TYPE(p);624construct_path_with_fanout(l->key_oid.hash, fanout,625path);626ret = fn(&l->key_oid, &l->val_oid, path,627cb_data);628break;629}630if (ret)631return ret;632}633return 0;634}
635
636struct tree_write_stack {637struct tree_write_stack *next;638struct strbuf buf;639char path[2]; /* path to subtree in next, if any */640};641
642static inline int matches_tree_write_stack(struct tree_write_stack *tws,643const char *full_path)644{
645return full_path[0] == tws->path[0] &&646full_path[1] == tws->path[1] &&647full_path[2] == '/';648}
649
650static void write_tree_entry(struct strbuf *buf, unsigned int mode,651const char *path, unsigned int path_len, const652unsigned char *hash)653{
654strbuf_addf(buf, "%o %.*s%c", mode, path_len, path, '\0');655strbuf_add(buf, hash, the_hash_algo->rawsz);656}
657
658static void tree_write_stack_init_subtree(struct tree_write_stack *tws,659const char *path)660{
661struct tree_write_stack *n;662assert(!tws->next);663assert(tws->path[0] == '\0' && tws->path[1] == '\0');664n = (struct tree_write_stack *)665xmalloc(sizeof(struct tree_write_stack));666n->next = NULL;667strbuf_init(&n->buf, 256 * (32 + the_hash_algo->hexsz)); /* assume 256 entries per tree */668n->path[0] = n->path[1] = '\0';669tws->next = n;670tws->path[0] = path[0];671tws->path[1] = path[1];672}
673
674static int tree_write_stack_finish_subtree(struct tree_write_stack *tws)675{
676int ret;677struct tree_write_stack *n = tws->next;678struct object_id s;679if (n) {680ret = tree_write_stack_finish_subtree(n);681if (ret)682return ret;683ret = write_object_file(n->buf.buf, n->buf.len, OBJ_TREE, &s);684if (ret)685return ret;686strbuf_release(&n->buf);687free(n);688tws->next = NULL;689write_tree_entry(&tws->buf, 040000, tws->path, 2, s.hash);690tws->path[0] = tws->path[1] = '\0';691}692return 0;693}
694
695static int write_each_note_helper(struct tree_write_stack *tws,696const char *path, unsigned int mode,697const struct object_id *oid)698{
699size_t path_len = strlen(path);700unsigned int n = 0;701int ret;702
703/* Determine common part of tree write stack */704while (tws && 3 * n < path_len &&705matches_tree_write_stack(tws, path + 3 * n)) {706n++;707tws = tws->next;708}709
710/* tws point to last matching tree_write_stack entry */711ret = tree_write_stack_finish_subtree(tws);712if (ret)713return ret;714
715/* Start subtrees needed to satisfy path */716while (3 * n + 2 < path_len && path[3 * n + 2] == '/') {717tree_write_stack_init_subtree(tws, path + 3 * n);718n++;719tws = tws->next;720}721
722/* There should be no more directory components in the given path */723assert(memchr(path + 3 * n, '/', path_len - (3 * n)) == NULL);724
725/* Finally add given entry to the current tree object */726write_tree_entry(&tws->buf, mode, path + 3 * n, path_len - (3 * n),727oid->hash);728
729return 0;730}
731
732struct write_each_note_data {733struct tree_write_stack *root;734struct non_note **nn_list;735struct non_note *nn_prev;736};737
738static int write_each_non_note_until(const char *note_path,739struct write_each_note_data *d)740{
741struct non_note *p = d->nn_prev;742struct non_note *n = p ? p->next : *d->nn_list;743int cmp = 0, ret;744while (n && (!note_path || (cmp = strcmp(n->path, note_path)) <= 0)) {745if (note_path && cmp == 0)746; /* do nothing, prefer note to non-note */747else {748ret = write_each_note_helper(d->root, n->path, n->mode,749&n->oid);750if (ret)751return ret;752}753p = n;754n = n->next;755}756d->nn_prev = p;757return 0;758}
759
760static int write_each_note(const struct object_id *object_oid UNUSED,761const struct object_id *note_oid, char *note_path,762void *cb_data)763{
764struct write_each_note_data *d =765(struct write_each_note_data *) cb_data;766size_t note_path_len = strlen(note_path);767unsigned int mode = 0100644;768
769if (note_path[note_path_len - 1] == '/') {770/* subtree entry */771note_path_len--;772note_path[note_path_len] = '\0';773mode = 040000;774}775assert(note_path_len <= GIT_MAX_HEXSZ + FANOUT_PATH_SEPARATORS);776
777/* Weave non-note entries into note entries */778return write_each_non_note_until(note_path, d) ||779write_each_note_helper(d->root, note_path, mode, note_oid);780}
781
782struct note_delete_list {783struct note_delete_list *next;784const unsigned char *sha1;785};786
787static int prune_notes_helper(const struct object_id *object_oid,788const struct object_id *note_oid UNUSED,789char *note_path UNUSED,790void *cb_data)791{
792struct note_delete_list **l = (struct note_delete_list **) cb_data;793struct note_delete_list *n;794
795if (repo_has_object_file(the_repository, object_oid))796return 0; /* nothing to do for this note */797
798/* failed to find object => prune this note */799n = (struct note_delete_list *) xmalloc(sizeof(*n));800n->next = *l;801n->sha1 = object_oid->hash;802*l = n;803return 0;804}
805
806int combine_notes_concatenate(struct object_id *cur_oid,807const struct object_id *new_oid)808{
809char *cur_msg = NULL, *new_msg = NULL, *buf;810unsigned long cur_len, new_len, buf_len;811enum object_type cur_type, new_type;812int ret;813
814/* read in both note blob objects */815if (!is_null_oid(new_oid))816new_msg = repo_read_object_file(the_repository, new_oid,817&new_type, &new_len);818if (!new_msg || !new_len || new_type != OBJ_BLOB) {819free(new_msg);820return 0;821}822if (!is_null_oid(cur_oid))823cur_msg = repo_read_object_file(the_repository, cur_oid,824&cur_type, &cur_len);825if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {826free(cur_msg);827free(new_msg);828oidcpy(cur_oid, new_oid);829return 0;830}831
832/* we will separate the notes by two newlines anyway */833if (cur_msg[cur_len - 1] == '\n')834cur_len--;835
836/* concatenate cur_msg and new_msg into buf */837buf_len = cur_len + 2 + new_len;838buf = (char *) xmalloc(buf_len);839memcpy(buf, cur_msg, cur_len);840buf[cur_len] = '\n';841buf[cur_len + 1] = '\n';842memcpy(buf + cur_len + 2, new_msg, new_len);843free(cur_msg);844free(new_msg);845
846/* create a new blob object from buf */847ret = write_object_file(buf, buf_len, OBJ_BLOB, cur_oid);848free(buf);849return ret;850}
851
852int combine_notes_overwrite(struct object_id *cur_oid,853const struct object_id *new_oid)854{
855oidcpy(cur_oid, new_oid);856return 0;857}
858
859int combine_notes_ignore(struct object_id *cur_oid UNUSED,860const struct object_id *new_oid UNUSED)861{
862return 0;863}
864
865/*
866* Add the lines from the named object to list, with trailing
867* newlines removed.
868*/
869static int string_list_add_note_lines(struct string_list *list,870const struct object_id *oid)871{
872char *data;873unsigned long len;874enum object_type t;875
876if (is_null_oid(oid))877return 0;878
879/* read_sha1_file NUL-terminates */880data = repo_read_object_file(the_repository, oid, &t, &len);881if (t != OBJ_BLOB || !data || !len) {882free(data);883return t != OBJ_BLOB || !data;884}885
886/*887* If the last line of the file is EOL-terminated, this will
888* add an empty string to the list. But it will be removed
889* later, along with any empty strings that came from empty
890* lines within the file.
891*/
892string_list_split(list, data, '\n', -1);893free(data);894return 0;895}
896
897static int string_list_join_lines_helper(struct string_list_item *item,898void *cb_data)899{
900struct strbuf *buf = cb_data;901strbuf_addstr(buf, item->string);902strbuf_addch(buf, '\n');903return 0;904}
905
906int combine_notes_cat_sort_uniq(struct object_id *cur_oid,907const struct object_id *new_oid)908{
909struct string_list sort_uniq_list = STRING_LIST_INIT_DUP;910struct strbuf buf = STRBUF_INIT;911int ret = 1;912
913/* read both note blob objects into unique_lines */914if (string_list_add_note_lines(&sort_uniq_list, cur_oid))915goto out;916if (string_list_add_note_lines(&sort_uniq_list, new_oid))917goto out;918string_list_remove_empty_items(&sort_uniq_list, 0);919string_list_sort(&sort_uniq_list);920string_list_remove_duplicates(&sort_uniq_list, 0);921
922/* create a new blob object from sort_uniq_list */923if (for_each_string_list(&sort_uniq_list,924string_list_join_lines_helper, &buf))925goto out;926
927ret = write_object_file(buf.buf, buf.len, OBJ_BLOB, cur_oid);928
929out:930strbuf_release(&buf);931string_list_clear(&sort_uniq_list, 0);932return ret;933}
934
935static int string_list_add_one_ref(const char *refname, const char *referent UNUSED,936const struct object_id *oid UNUSED,937int flag UNUSED, void *cb)938{
939struct string_list *refs = cb;940if (!unsorted_string_list_has_string(refs, refname))941string_list_append(refs, refname);942return 0;943}
944
945/*
946* The list argument must have strdup_strings set on it.
947*/
948void string_list_add_refs_by_glob(struct string_list *list, const char *glob)949{
950assert(list->strdup_strings);951if (has_glob_specials(glob)) {952refs_for_each_glob_ref(get_main_ref_store(the_repository),953string_list_add_one_ref, glob, list);954} else {955struct object_id oid;956if (repo_get_oid(the_repository, glob, &oid))957warning("notes ref %s is invalid", glob);958if (!unsorted_string_list_has_string(list, glob))959string_list_append(list, glob);960}961}
962
963void string_list_add_refs_from_colon_sep(struct string_list *list,964const char *globs)965{
966struct string_list split = STRING_LIST_INIT_NODUP;967char *globs_copy = xstrdup(globs);968int i;969
970string_list_split_in_place(&split, globs_copy, ":", -1);971string_list_remove_empty_items(&split, 0);972
973for (i = 0; i < split.nr; i++)974string_list_add_refs_by_glob(list, split.items[i].string);975
976string_list_clear(&split, 0);977free(globs_copy);978}
979
980static int notes_display_config(const char *k, const char *v,981const struct config_context *ctx UNUSED,982void *cb)983{
984int *load_refs = cb;985
986if (*load_refs && !strcmp(k, "notes.displayref")) {987if (!v)988return config_error_nonbool(k);989string_list_add_refs_by_glob(&display_notes_refs, v);990}991
992return 0;993}
994
995const char *default_notes_ref(void)996{
997const char *notes_ref = NULL;998if (!notes_ref)999notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);1000if (!notes_ref)1001notes_ref = notes_ref_name; /* value of core.notesRef config */1002if (!notes_ref)1003notes_ref = GIT_NOTES_DEFAULT_REF;1004return notes_ref;1005}
1006
1007void init_notes(struct notes_tree *t, const char *notes_ref,1008combine_notes_fn combine_notes, int flags)1009{
1010struct object_id oid, object_oid;1011unsigned short mode;1012struct leaf_node root_tree;1013
1014if (!t)1015t = &default_notes_tree;1016assert(!t->initialized);1017
1018if (!notes_ref)1019notes_ref = default_notes_ref();1020update_ref_namespace(NAMESPACE_NOTES, xstrdup(notes_ref));1021
1022if (!combine_notes)1023combine_notes = combine_notes_concatenate;1024
1025t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));1026t->first_non_note = NULL;1027t->prev_non_note = NULL;1028t->ref = xstrdup(notes_ref);1029t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;1030t->combine_notes = combine_notes;1031t->initialized = 1;1032t->dirty = 0;1033
1034if (flags & NOTES_INIT_EMPTY ||1035repo_get_oid_treeish(the_repository, notes_ref, &object_oid))1036return;1037if (flags & NOTES_INIT_WRITABLE && refs_read_ref(get_main_ref_store(the_repository), notes_ref, &object_oid))1038die("Cannot use notes ref %s", notes_ref);1039if (get_tree_entry(the_repository, &object_oid, "", &oid, &mode))1040die("Failed to read notes tree referenced by %s (%s)",1041notes_ref, oid_to_hex(&object_oid));1042
1043oidclr(&root_tree.key_oid, the_repository->hash_algo);1044oidcpy(&root_tree.val_oid, &oid);1045load_subtree(t, &root_tree, t->root, 0);1046}
1047
1048struct notes_tree **load_notes_trees(struct string_list *refs, int flags)1049{
1050struct string_list_item *item;1051int counter = 0;1052struct notes_tree **trees;1053ALLOC_ARRAY(trees, refs->nr + 1);1054for_each_string_list_item(item, refs) {1055struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));1056init_notes(t, item->string, combine_notes_ignore, flags);1057trees[counter++] = t;1058}1059trees[counter] = NULL;1060return trees;1061}
1062
1063void init_display_notes(struct display_notes_opt *opt)1064{
1065memset(opt, 0, sizeof(*opt));1066opt->use_default_notes = -1;1067string_list_init_dup(&opt->extra_notes_refs);1068}
1069
1070void release_display_notes(struct display_notes_opt *opt)1071{
1072string_list_clear(&opt->extra_notes_refs, 0);1073}
1074
1075void enable_default_display_notes(struct display_notes_opt *opt, int *show_notes)1076{
1077opt->use_default_notes = 1;1078*show_notes = 1;1079}
1080
1081void enable_ref_display_notes(struct display_notes_opt *opt, int *show_notes,1082const char *ref) {1083struct strbuf buf = STRBUF_INIT;1084strbuf_addstr(&buf, ref);1085expand_notes_ref(&buf);1086string_list_append_nodup(&opt->extra_notes_refs,1087strbuf_detach(&buf, NULL));1088*show_notes = 1;1089}
1090
1091void disable_display_notes(struct display_notes_opt *opt, int *show_notes)1092{
1093opt->use_default_notes = -1;1094string_list_clear(&opt->extra_notes_refs, 0);1095*show_notes = 0;1096}
1097
1098void load_display_notes(struct display_notes_opt *opt)1099{
1100char *display_ref_env;1101int load_config_refs = 0;1102display_notes_refs.strdup_strings = 1;1103
1104assert(!display_notes_trees);1105
1106if (!opt || opt->use_default_notes > 0 ||1107(opt->use_default_notes == -1 && !opt->extra_notes_refs.nr)) {1108string_list_append(&display_notes_refs, default_notes_ref());1109display_ref_env = getenv(GIT_NOTES_DISPLAY_REF_ENVIRONMENT);1110if (display_ref_env) {1111string_list_add_refs_from_colon_sep(&display_notes_refs,1112display_ref_env);1113load_config_refs = 0;1114} else1115load_config_refs = 1;1116}1117
1118git_config(notes_display_config, &load_config_refs);1119
1120if (opt) {1121struct string_list_item *item;1122for_each_string_list_item(item, &opt->extra_notes_refs)1123string_list_add_refs_by_glob(&display_notes_refs,1124item->string);1125}1126
1127display_notes_trees = load_notes_trees(&display_notes_refs, 0);1128string_list_clear(&display_notes_refs, 0);1129}
1130
1131int add_note(struct notes_tree *t, const struct object_id *object_oid,1132const struct object_id *note_oid, combine_notes_fn combine_notes)1133{
1134struct leaf_node *l;1135
1136if (!t)1137t = &default_notes_tree;1138assert(t->initialized);1139t->dirty = 1;1140if (!combine_notes)1141combine_notes = t->combine_notes;1142l = (struct leaf_node *) xmalloc(sizeof(struct leaf_node));1143oidcpy(&l->key_oid, object_oid);1144oidcpy(&l->val_oid, note_oid);1145return note_tree_insert(t, t->root, 0, l, PTR_TYPE_NOTE, combine_notes);1146}
1147
1148int remove_note(struct notes_tree *t, const unsigned char *object_sha1)1149{
1150struct leaf_node l;1151
1152if (!t)1153t = &default_notes_tree;1154assert(t->initialized);1155oidread(&l.key_oid, object_sha1, the_repository->hash_algo);1156oidclr(&l.val_oid, the_repository->hash_algo);1157note_tree_remove(t, t->root, 0, &l);1158if (is_null_oid(&l.val_oid)) /* no note was removed */1159return 1;1160t->dirty = 1;1161return 0;1162}
1163
1164const struct object_id *get_note(struct notes_tree *t,1165const struct object_id *oid)1166{
1167struct leaf_node *found;1168
1169if (!t)1170t = &default_notes_tree;1171assert(t->initialized);1172found = note_tree_find(t, t->root, 0, oid->hash);1173return found ? &found->val_oid : NULL;1174}
1175
1176int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,1177void *cb_data)1178{
1179if (!t)1180t = &default_notes_tree;1181assert(t->initialized);1182return for_each_note_helper(t, t->root, 0, 0, flags, fn, cb_data);1183}
1184
1185int write_notes_tree(struct notes_tree *t, struct object_id *result)1186{
1187struct tree_write_stack root;1188struct write_each_note_data cb_data;1189int ret;1190int flags;1191
1192if (!t)1193t = &default_notes_tree;1194assert(t->initialized);1195
1196/* Prepare for traversal of current notes tree */1197root.next = NULL; /* last forward entry in list is grounded */1198strbuf_init(&root.buf, 256 * (32 + the_hash_algo->hexsz)); /* assume 256 entries */1199root.path[0] = root.path[1] = '\0';1200cb_data.root = &root;1201cb_data.nn_list = &(t->first_non_note);1202cb_data.nn_prev = NULL;1203
1204/* Write tree objects representing current notes tree */1205flags = FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |1206FOR_EACH_NOTE_YIELD_SUBTREES;1207ret = for_each_note(t, flags, write_each_note, &cb_data) ||1208write_each_non_note_until(NULL, &cb_data) ||1209tree_write_stack_finish_subtree(&root) ||1210write_object_file(root.buf.buf, root.buf.len, OBJ_TREE, result);1211strbuf_release(&root.buf);1212return ret;1213}
1214
1215void prune_notes(struct notes_tree *t, int flags)1216{
1217struct note_delete_list *l = NULL;1218
1219if (!t)1220t = &default_notes_tree;1221assert(t->initialized);1222
1223for_each_note(t, 0, prune_notes_helper, &l);1224
1225while (l) {1226struct note_delete_list *next;1227
1228if (flags & NOTES_PRUNE_VERBOSE)1229printf("%s\n", hash_to_hex(l->sha1));1230if (!(flags & NOTES_PRUNE_DRYRUN))1231remove_note(t, l->sha1);1232
1233next = l->next;1234free(l);1235l = next;1236}1237}
1238
1239void free_notes(struct notes_tree *t)1240{
1241if (!t)1242t = &default_notes_tree;1243if (t->root)1244note_tree_free(t->root);1245free(t->root);1246while (t->first_non_note) {1247t->prev_non_note = t->first_non_note->next;1248free(t->first_non_note->path);1249free(t->first_non_note);1250t->first_non_note = t->prev_non_note;1251}1252free(t->ref);1253memset(t, 0, sizeof(struct notes_tree));1254}
1255
1256/*
1257* Fill the given strbuf with the notes associated with the given object.
1258*
1259* If the given notes_tree structure is not initialized, it will be auto-
1260* initialized to the default value (see documentation for init_notes() above).
1261* If the given notes_tree is NULL, the internal/default notes_tree will be
1262* used instead.
1263*
1264* (raw != 0) gives the %N userformat; otherwise, the note message is given
1265* for human consumption.
1266*/
1267static void format_note(struct notes_tree *t, const struct object_id *object_oid,1268struct strbuf *sb, const char *output_encoding, int raw)1269{
1270static const char utf8[] = "utf-8";1271const struct object_id *oid;1272char *msg, *msg_p;1273unsigned long linelen, msglen;1274enum object_type type;1275
1276if (!t)1277t = &default_notes_tree;1278if (!t->initialized)1279init_notes(t, NULL, NULL, 0);1280
1281oid = get_note(t, object_oid);1282if (!oid)1283return;1284
1285if (!(msg = repo_read_object_file(the_repository, oid, &type, &msglen)) || type != OBJ_BLOB) {1286free(msg);1287return;1288}1289
1290if (output_encoding && *output_encoding &&1291!is_encoding_utf8(output_encoding)) {1292char *reencoded = reencode_string(msg, output_encoding, utf8);1293if (reencoded) {1294free(msg);1295msg = reencoded;1296msglen = strlen(msg);1297}1298}1299
1300/* we will end the annotation by a newline anyway */1301if (msglen && msg[msglen - 1] == '\n')1302msglen--;1303
1304if (!raw) {1305const char *ref = t->ref;1306if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) {1307strbuf_addstr(sb, "\nNotes:\n");1308} else {1309skip_prefix(ref, "refs/", &ref);1310skip_prefix(ref, "notes/", &ref);1311strbuf_addf(sb, "\nNotes (%s):\n", ref);1312}1313}1314
1315for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {1316linelen = strchrnul(msg_p, '\n') - msg_p;1317
1318if (!raw)1319strbuf_addstr(sb, " ");1320strbuf_add(sb, msg_p, linelen);1321strbuf_addch(sb, '\n');1322}1323
1324free(msg);1325}
1326
1327void format_display_notes(const struct object_id *object_oid,1328struct strbuf *sb, const char *output_encoding, int raw)1329{
1330int i;1331assert(display_notes_trees);1332for (i = 0; display_notes_trees[i]; i++)1333format_note(display_notes_trees[i], object_oid, sb,1334output_encoding, raw);1335}
1336
1337int copy_note(struct notes_tree *t,1338const struct object_id *from_obj, const struct object_id *to_obj,1339int force, combine_notes_fn combine_notes)1340{
1341const struct object_id *note = get_note(t, from_obj);1342const struct object_id *existing_note = get_note(t, to_obj);1343
1344if (!force && existing_note)1345return 1;1346
1347if (note)1348return add_note(t, to_obj, note, combine_notes);1349else if (existing_note)1350return add_note(t, to_obj, null_oid(), combine_notes);1351
1352return 0;1353}
1354
1355void expand_notes_ref(struct strbuf *sb)1356{
1357if (starts_with(sb->buf, "refs/notes/"))1358return; /* we're happy */1359else if (starts_with(sb->buf, "notes/"))1360strbuf_insertstr(sb, 0, "refs/");1361else1362strbuf_insertstr(sb, 0, "refs/notes/");1363}
1364
1365void expand_loose_notes_ref(struct strbuf *sb)1366{
1367struct object_id object;1368
1369if (repo_get_oid(the_repository, sb->buf, &object)) {1370/* fallback to expand_notes_ref */1371expand_notes_ref(sb);1372}1373}
1374