split-index: strip pathname of on-disk replaced entries

We know the positions of replaced entries via the replace bitmap in "link" extension, so the "name" path does not have to be stored (it's still in the shared index). With this, we also have a way to distinguish additions vs replacements at load time and can catch broken "link" extensions. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Jun 13, 2014 at 19:19 UTC b3c96fb158f05152336f167076f5d81d23c3a5e5
3 files changed +23 -2
cache.h
+1
@@ -170,6 +170,7 @@ struct cache_entry {
170 #define CE_MATCHED (1 << 26)
171
172 #define CE_UPDATE_IN_BASE (1 << 27)
173 +#define CE_STRIP_NAME (1 << 28)
174
175 /*
176 * Extended on-disk flags
read-cache.c
+10
@@ -1787,9 +1787,15 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
1787 {
1788 int size;
1789 struct ondisk_cache_entry *ondisk;
1790 + int saved_namelen = saved_namelen; /* compiler workaround */
1791 char *name;
1792 int result;
1793
1794 + if (ce->ce_flags & CE_STRIP_NAME) {
1795 + saved_namelen = ce_namelen(ce);
1796 + ce->ce_namelen = 0;
1797 + }
1798 +
1799 if (!previous_name) {
1800 size = ondisk_ce_size(ce);
1801 ondisk = xcalloc(1, size);
@@ -1821,6 +1827,10 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
1827 strbuf_splice(previous_name, common, to_remove,
1828 ce->name + common, ce_namelen(ce) - common);
1829 }
1830 + if (ce->ce_flags & CE_STRIP_NAME) {
1831 + ce->ce_namelen = saved_namelen;
1832 + ce->ce_flags &= ~CE_STRIP_NAME;
1833 + }
1834
1835 result = ce_write(c, fd, ondisk, size);
1836 free(ondisk);
split-index.c
+12 -2
@@ -89,6 +89,7 @@ static void replace_entry(size_t pos, void *data)
89 struct index_state *istate = data;
90 struct split_index *si = istate->split_index;
91 struct cache_entry *dst, *src;
92 +
93 if (pos >= istate->cache_nr)
94 die("position for replacement %d exceeds base index size %d",
95 (int)pos, istate->cache_nr);
@@ -100,10 +101,14 @@ static void replace_entry(size_t pos, void *data)
101 die("entry %d is marked as both replaced and deleted",
102 (int)pos);
103 src = si->saved_cache[si->nr_replacements];
104 + if (ce_namelen(src))
105 + die("corrupt link extension, entry %d should have "
106 + "zero length name", (int)pos);
107 src->index = pos + 1;
108 src->ce_flags |= CE_UPDATE_IN_BASE;
105 - free(dst);
106 - dst = src;
109 + src->ce_namelen = dst->ce_namelen;
110 + copy_cache_entry(dst, src);
111 + free(src);
112 si->nr_replacements++;
113 }
114
@@ -131,6 +136,9 @@ void merge_base_index(struct index_state *istate)
136 remove_marked_cache_entries(istate);
137
138 for (i = si->nr_replacements; i < si->saved_cache_nr; i++) {
139 + if (!ce_namelen(si->saved_cache[i]))
140 + die("corrupt link extension, entry %d should "
141 + "have non-zero length name", i);
142 add_index_entry(istate, si->saved_cache[i],
143 ADD_CACHE_OK_TO_ADD |
144 ADD_CACHE_KEEP_CACHE_TREE |
@@ -213,6 +221,7 @@ void prepare_to_write_split_index(struct index_state *istate)
221 ewah_set(si->delete_bitmap, i);
222 else if (ce->ce_flags & CE_UPDATE_IN_BASE) {
223 ewah_set(si->replace_bitmap, i);
224 + ce->ce_flags |= CE_STRIP_NAME;
225 ALLOC_GROW(entries, nr_entries+1, nr_alloc);
226 entries[nr_entries++] = ce;
227 }
@@ -222,6 +231,7 @@ void prepare_to_write_split_index(struct index_state *istate)
231 for (i = 0; i < istate->cache_nr; i++) {
232 ce = istate->cache[i];
233 if ((!si->base || !ce->index) && !(ce->ce_flags & CE_REMOVE)) {
234 + assert(!(ce->ce_flags & CE_STRIP_NAME));
235 ALLOC_GROW(entries, nr_entries+1, nr_alloc);
236 entries[nr_entries++] = ce;
237 }