Make git read the resolve-undo data from the index. Since the resolve-undo data is joined with the conflicts in the ondisk format of the index file version 5, conflicts and resolved data is read at the same time, and the resolve-undo data is then converted to the in-memory format. Helped-by: Thomas Rast <trast@xxxxxxxxxxxxxxx> Signed-off-by: Thomas Gummerer <t.gummerer@xxxxxxxxx> --- read-cache-v5.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 191 insertions(+), 8 deletions(-) diff --git a/read-cache-v5.c b/read-cache-v5.c index 0d06cfe..a5e9b5a 100644 --- a/read-cache-v5.c +++ b/read-cache-v5.c @@ -723,6 +723,29 @@ static void ondisk_from_directory_entry(struct directory_entry *de, } } +static struct conflict_part *conflict_part_from_inmemory(struct cache_entry *ce) +{ + struct conflict_part *conflict; + int flags; + + conflict = xmalloc(sizeof(struct conflict_part)); + flags = CONFLICT_CONFLICTED; + flags |= ce_stage(ce) << CONFLICT_STAGESHIFT; + conflict->flags = flags; + conflict->entry_mode = ce->ce_mode; + conflict->next = NULL; + hashcpy(conflict->sha1, ce->sha1); + return conflict; +} + +static void conflict_to_ondisk(struct conflict_part *cp, + struct ondisk_conflict_part *ondisk) +{ + ondisk->flags = htons(cp->flags); + ondisk->entry_mode = htons(cp->entry_mode); + hashcpy(ondisk->sha1, cp->sha1); +} + static void insert_directory_entry(struct directory_entry *de, struct hash_table *table, unsigned int *total_dir_len, @@ -789,6 +812,11 @@ static struct directory_entry *get_directory(char *dir, unsigned int dir_len, return ret; } +static struct conflict_entry *create_conflict_entry_from_ce(struct cache_entry *ce) +{ + return create_new_conflict(ce->name, ce_namelen(ce)); +} + static void convert_one_to_ondisk(struct hash_table *table, struct cache_tree *it, const char *path, int pathlen, uint32_t crc) { @@ -840,6 +868,52 @@ static void cache_tree_to_ondisk(struct hash_table *table, struct cache_tree *ro convert_one_to_ondisk(table, root, "", 0, 0); } +static void resolve_undo_to_ondisk(struct string_list *resolve_undo, + struct conflict_entry **conflict_queue) +{ + struct string_list_item *item; + struct conflict_entry *current = *conflict_queue; + + if (!resolve_undo) + return; + for_each_string_list_item(item, resolve_undo) { + struct conflict_entry *conflict_entry; + struct resolve_undo_info *ui = item->util; + int i, len; + + if (!ui) + continue; + + len = strlen(item->string); + while (current && current->next && + cache_name_compare(current->name, current->namelen, + item->string, len)) + current = current->next; + + conflict_entry = create_new_conflict(item->string, len); + for (i = 0; i < 3; i++) { + if (ui->mode[i]) { + struct conflict_part *cp; + + cp = xmalloc(sizeof(struct conflict_part)); + cp->flags = (i + 1) << CONFLICT_STAGESHIFT; + cp->entry_mode = ui->mode[i]; + cp->next = NULL; + hashcpy(cp->sha1, ui->sha1[i]); + add_part_to_conflict_entry(conflict_entry, cp); + } + } + if (!*conflict_queue) { + *conflict_queue = conflict_entry; + conflict_entry->next = NULL; + current = conflict_entry; + } else { + conflict_entry->next = current->next; + current->next = conflict_entry; + } + } +} + static void ce_queue_push(struct cache_entry **head, struct cache_entry **tail, struct cache_entry *ce) @@ -855,15 +929,32 @@ static void ce_queue_push(struct cache_entry **head, *tail = (*tail)->next_ce; } +static void conflict_queue_push(struct conflict_entry **head, + struct conflict_entry **tail, + struct conflict_entry *conflict) +{ + if (!*head) { + *head = *tail = conflict; + (*tail)->next = NULL; + return; + } + + (*tail)->next = conflict; + conflict->next = NULL; + *tail = (*tail)->next; +} + static struct directory_entry *compile_directory_data(struct index_state *istate, int nfile, unsigned int *ndir, unsigned int *total_dir_len, - unsigned int *total_file_len) + unsigned int *total_file_len, + struct conflict_entry **conflict_queue) { int i, dir_len = -1; char *dir; struct directory_entry *de, *current, *search; struct cache_entry **cache = istate->cache; + struct conflict_entry *conflict_entry = NULL, *tail; struct hash_table table; uint32_t crc; @@ -894,9 +985,22 @@ static struct directory_entry *compile_directory_data(struct index_state *istate if (search->de_pathlen) *total_file_len -= search->de_pathlen + 1; ce_queue_push(&(search->ce), &(search->ce_last), cache[i]); + + if (ce_stage(cache[i]) > 0) { + struct conflict_part *conflict_part; + if (!conflict_entry || + cache_name_compare(conflict_entry->name, conflict_entry->namelen, + cache[i]->name, ce_namelen(cache[i]))) { + conflict_entry = create_conflict_entry_from_ce(cache[i]); + conflict_queue_push(conflict_queue, &tail, conflict_entry); + } + conflict_part = conflict_part_from_inmemory(cache[i]); + add_part_to_conflict_entry(conflict_entry, conflict_part); + } } if (istate->cache_tree) cache_tree_to_ondisk(&table, istate->cache_tree); + resolve_undo_to_ondisk(istate->resolve_undo, conflict_queue); return de; } @@ -1062,16 +1166,82 @@ static int write_entries(struct index_state *istate, return 0; } +static int write_conflict(struct conflict_entry *conflict, int fd) +{ + struct conflict_entry *current; + struct conflict_part *current_part; + uint32_t crc; + + current = conflict; + while (current) { + unsigned int to_write, i; + + crc = 0; + if (ce_write(&crc, fd, current->name, current->namelen) < 0) + return -1; + if (ce_write(&crc, fd, "\0", 1) < 0) + return -1; + to_write = htonl(current->nfileconflicts); + if (ce_write(&crc, fd, (Bytef*)&to_write, 4) < 0) + return -1; + current_part = current->entries; + for (i = 0; i < current->nfileconflicts; i++) { + struct ondisk_conflict_part ondisk; + + conflict_to_ondisk(current_part, &ondisk); + if (ce_write(&crc, fd, (Bytef*)&ondisk, sizeof(struct ondisk_conflict_part)) < 0) + return 0; + current_part = current_part->next; + } + crc = htonl(crc); + if (ce_write(NULL, fd, &crc, 4) < 0) + return -1; + current = current->next; + } + return 0; +} + +static int write_resolve_undo(struct index_state *istate, + struct conflict_entry *conflict_queue, + int fd) +{ + struct conflict_entry *current; + int nr = 0; + uint32_t crc = 0, to_write; + + /* Just count */ + for (current = conflict_queue; current; current = current->next) + nr++; + + if (ce_write(&crc, fd, "REUC", 4) < 0) + return -1; + to_write = htonl(nr); + if (ce_write(&crc, fd, &to_write, 4) < 0) + return -1; + to_write = htonl(crc); + if (ce_write(NULL, fd, &to_write, 4) < 0) + return -1; + + current = conflict_queue; + while (current) { + if (write_conflict(current, fd) < 0) + return -1; + current = current->next; + } + return 0; +} + static int write_index_v5(struct index_state *istate, int newfd) { struct cache_header hdr; struct cache_header_v5 hdr_v5; struct cache_entry **cache = istate->cache; struct directory_entry *de; + struct conflict_entry *conflict_queue = NULL; unsigned int entries = istate->cache_nr; unsigned int i, removed, total_dir_len; unsigned int total_file_len, foffsetblock; - unsigned int ndir; + unsigned int ndir, extoffset, nextension; uint32_t crc; if (istate->filter_opts) @@ -1084,24 +1254,34 @@ static int write_index_v5(struct index_state *istate, int newfd) hdr.hdr_signature = htonl(CACHE_SIGNATURE); hdr.hdr_version = htonl(istate->version); hdr.hdr_entries = htonl(entries - removed); - hdr_v5.hdr_nextension = htonl(0); /* Currently no extensions are supported */ total_dir_len = 0; total_file_len = 0; de = compile_directory_data(istate, entries, &ndir, - &total_dir_len, &total_file_len); + &total_dir_len, &total_file_len, + &conflict_queue); hdr_v5.hdr_ndir = htonl(ndir); - foffsetblock = sizeof(hdr) + sizeof(hdr_v5) + 4 - + (ndir + 1) * 4 - + total_dir_len - + ndir * (offsetof(struct ondisk_directory_entry, name) + 4); + nextension = (istate->resolve_undo || conflict_queue) ? 1 : 0; + foffsetblock = sizeof(hdr) + sizeof(hdr_v5) + (nextension * 4) + 4 + + (ndir + 1) * 4 + total_dir_len + + ndir * (offsetof(struct ondisk_directory_entry, name) + 4); hdr_v5.hdr_fblockoffset = htonl(foffsetblock + (entries - removed + 1) * 4); + hdr_v5.hdr_nextension = htonl(nextension); + crc = 0; if (ce_write(&crc, newfd, &hdr, sizeof(hdr)) < 0) return -1; if (ce_write(&crc, newfd, &hdr_v5, sizeof(hdr_v5)) < 0) return -1; + + if (nextension) { + extoffset = foffsetblock + (entries - removed + 1) * 4 + total_file_len + + (entries - removed) * (offsetof(struct ondisk_cache_entry, name) + 4); + extoffset = htonl(extoffset); + if (ce_write(&crc, newfd, &extoffset, 4) < 0) + return -1; + } crc = htonl(crc); if (ce_write(NULL, newfd, &crc, 4) < 0) return -1; @@ -1110,6 +1290,9 @@ static int write_index_v5(struct index_state *istate, int newfd) return -1; if (write_entries(istate, de, entries, newfd) < 0) return -1; + if (nextension) + if (write_resolve_undo(istate, conflict_queue, newfd) < 0) + return -1; return ce_flush(newfd); } -- 1.8.4.2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html