245
const char *name;
246
struct tree_entry branch_tree;
247
uintmax_t last_commit;
248
+ uintmax_t num_notes;
249
unsigned active : 1;
250
unsigned pack_id : PACK_ID_BITS;
251
unsigned char sha1[20];
694
b->table_next_branch = branch_table[hc];
695
b->branch_tree.versions[0].mode = S_IFDIR;
696
b->branch_tree.versions[1].mode = S_IFDIR;
697
+ b->num_notes = 0;
698
b->active = 0;
699
b->pack_id = MAX_PACK_ID;
700
branch_table[hc] = b;
1862
}
1863
}
1864
1865
+static unsigned char convert_num_notes_to_fanout(uintmax_t num_notes)
1866
+{
1867
+ unsigned char fanout = 0;
1868
+ while ((num_notes >>= 8))
1869
+ fanout++;
1870
+ return fanout;
1871
+}
1872
+
1873
+static void construct_path_with_fanout(const char *hex_sha1,
1874
+ unsigned char fanout, char *path)
1875
+{
1876
+ unsigned int i = 0, j = 0;
1877
+ if (fanout >= 20)
1878
+ die("Too large fanout (%u)", fanout);
1879
+ while (fanout) {
1880
+ path[i++] = hex_sha1[j++];
1881
+ path[i++] = hex_sha1[j++];
1882
+ path[i++] = '/';
1883
+ fanout--;
1884
+ }
1885
+ memcpy(path + i, hex_sha1 + j, 40 - j);
1886
+ path[i + 40 - j] = '\0';
1887
+}
1888
+
1889
+static uintmax_t do_change_note_fanout(
1890
+ struct tree_entry *orig_root, struct tree_entry *root,
1891
+ char *hex_sha1, unsigned int hex_sha1_len,
1892
+ char *fullpath, unsigned int fullpath_len,
1893
+ unsigned char fanout)
1894
+{
1895
+ struct tree_content *t = root->tree;
1896
+ struct tree_entry *e, leaf;
1897
+ unsigned int i, tmp_hex_sha1_len, tmp_fullpath_len;
1898
+ uintmax_t num_notes = 0;
1899
+ unsigned char sha1[20];
1900
+ char realpath[60];
1901
+
1902
+ for (i = 0; t && i < t->entry_count; i++) {
1903
+ e = t->entries[i];
1904
+ tmp_hex_sha1_len = hex_sha1_len + e->name->str_len;
1905
+ tmp_fullpath_len = fullpath_len;
1906
+
1907
+ /*
1908
+ * We're interested in EITHER existing note entries (entries
1909
+ * with exactly 40 hex chars in path, not including directory
1910
+ * separators), OR directory entries that may contain note
1911
+ * entries (with < 40 hex chars in path).
1912
+ * Also, each path component in a note entry must be a multiple
1913
+ * of 2 chars.
1914
+ */
1915
+ if (!e->versions[1].mode ||
1916
+ tmp_hex_sha1_len > 40 ||
1917
+ e->name->str_len % 2)
1918
+ continue;
1919
+
1920
+ /* This _may_ be a note entry, or a subdir containing notes */
1921
+ memcpy(hex_sha1 + hex_sha1_len, e->name->str_dat,
1922
+ e->name->str_len);
1923
+ if (tmp_fullpath_len)
1924
+ fullpath[tmp_fullpath_len++] = '/';
1925
+ memcpy(fullpath + tmp_fullpath_len, e->name->str_dat,
1926
+ e->name->str_len);
1927
+ tmp_fullpath_len += e->name->str_len;
1928
+ fullpath[tmp_fullpath_len] = '\0';
1929
+
1930
+ if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) {
1931
+ /* This is a note entry */
1932
+ construct_path_with_fanout(hex_sha1, fanout, realpath);
1933
+ if (!strcmp(fullpath, realpath)) {
1934
+ /* Note entry is in correct location */
1935
+ num_notes++;
1936
+ continue;
1937
+ }
1938
+
1939
+ /* Rename fullpath to realpath */
1940
+ if (!tree_content_remove(orig_root, fullpath, &leaf))
1941
+ die("Failed to remove path %s", fullpath);
1942
+ tree_content_set(orig_root, realpath,
1943
+ leaf.versions[1].sha1,
1944
+ leaf.versions[1].mode,
1945
+ leaf.tree);
1946
+ } else if (S_ISDIR(e->versions[1].mode)) {
1947
+ /* This is a subdir that may contain note entries */
1948
+ if (!e->tree)
1949
+ load_tree(e);
1950
+ num_notes += do_change_note_fanout(orig_root, e,
1951
+ hex_sha1, tmp_hex_sha1_len,
1952
+ fullpath, tmp_fullpath_len, fanout);
1953
+ }
1954
+
1955
+ /* The above may have reallocated the current tree_content */
1956
+ t = root->tree;
1957
+ }
1958
+ return num_notes;
1959
+}
1960
+
1961
+static uintmax_t change_note_fanout(struct tree_entry *root,
1962
+ unsigned char fanout)
1963
+{
1964
+ char hex_sha1[40], path[60];
1965
+ return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout);
1966
+}
1967
+
1968
static void file_change_m(struct branch *b)
1969
{
1970
const char *p = command_buf.buf + 2;
2115
leaf.tree);
2116
}
2117
2013
-static void note_change_n(struct branch *b)
2118
+static void note_change_n(struct branch *b, unsigned char old_fanout)
2119
{
2120
const char *p = command_buf.buf + 2;
2121
static struct strbuf uq = STRBUF_INIT;
2122
struct object_entry *oe = oe;
2123
struct branch *s;
2124
unsigned char sha1[20], commit_sha1[20];
2125
+ char path[60];
2126
uint16_t inline_data = 0;
2127
+ unsigned char new_fanout;
2128
2129
/* <dataref> or 'inline' */
2130
if (*p == ':') {
2178
if (oe->type != OBJ_BLOB)
2179
die("Not a blob (actually a %s): %s",
2180
typename(oe->type), command_buf.buf);
2074
- } else {
2181
+ } else if (!is_null_sha1(sha1)) {
2182
enum object_type type = sha1_object_info(sha1, NULL);
2183
if (type < 0)
2184
die("Blob not found: %s", command_buf.buf);
2187
typename(type), command_buf.buf);
2188
}
2189
2083
- tree_content_set(&b->branch_tree, sha1_to_hex(commit_sha1), sha1,
2084
- S_IFREG | 0644, NULL);
2190
+ construct_path_with_fanout(sha1_to_hex(commit_sha1), old_fanout, path);
2191
+ if (tree_content_remove(&b->branch_tree, path, NULL))
2192
+ b->num_notes--;
2193
+
2194
+ if (is_null_sha1(sha1))
2195
+ return; /* nothing to insert */
2196
+
2197
+ b->num_notes++;
2198
+ new_fanout = convert_num_notes_to_fanout(b->num_notes);
2199
+ construct_path_with_fanout(sha1_to_hex(commit_sha1), new_fanout, path);
2200
+ tree_content_set(&b->branch_tree, path, sha1, S_IFREG | 0644, NULL);
2201
}
2202
2203
static void file_change_deleteall(struct branch *b)
2206
hashclr(b->branch_tree.versions[0].sha1);
2207
hashclr(b->branch_tree.versions[1].sha1);
2208
load_tree(&b->branch_tree);
2209
+ b->num_notes = 0;
2210
}
2211
2212
static void parse_from_commit(struct branch *b, char *buf, unsigned long size)
2330
char *committer = NULL;
2331
struct hash_list *merge_list = NULL;
2332
unsigned int merge_count;
2333
+ unsigned char prev_fanout, new_fanout;
2334
2335
/* Obtain the branch name from the rest of our command */
2336
sp = strchr(command_buf.buf, ' ') + 1;
2361
load_branch(b);
2362
}
2363
2364
+ prev_fanout = convert_num_notes_to_fanout(b->num_notes);
2365
+
2366
/* file_change* */
2367
while (command_buf.len > 0) {
2368
if (!prefixcmp(command_buf.buf, "M "))
2374
else if (!prefixcmp(command_buf.buf, "C "))
2375
file_change_cr(b, 0);
2376
else if (!prefixcmp(command_buf.buf, "N "))
2257
- note_change_n(b);
2377
+ note_change_n(b, prev_fanout);
2378
else if (!strcmp("deleteall", command_buf.buf))
2379
file_change_deleteall(b);
2380
else {
2385
break;
2386
}
2387
2388
+ new_fanout = convert_num_notes_to_fanout(b->num_notes);
2389
+ if (new_fanout != prev_fanout)
2390
+ b->num_notes = change_note_fanout(&b->branch_tree, new_fanout);
2391
+
2392
/* build the tree and the commit */
2393
store_tree(&b->branch_tree);
2394
hashcpy(b->branch_tree.versions[0].sha1,