resolve-undo: record resolved conflicts in a new index extension section
[git] / resolve-undo.c
1 #include "cache.h"
2 #include "resolve-undo.h"
3 #include "string-list.h"
4
5 /* The only error case is to run out of memory in string-list */
6 void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
7 {
8         struct string_list_item *lost;
9         struct resolve_undo_info *ui;
10         struct string_list *resolve_undo;
11         int stage = ce_stage(ce);
12
13         if (!stage)
14                 return;
15
16         if (!istate->resolve_undo) {
17                 resolve_undo = xcalloc(1, sizeof(*resolve_undo));
18                 resolve_undo->strdup_strings = 1;
19                 istate->resolve_undo = resolve_undo;
20         }
21         resolve_undo = istate->resolve_undo;
22         lost = string_list_insert(ce->name, resolve_undo);
23         if (!lost->util)
24                 lost->util = xcalloc(1, sizeof(*ui));
25         ui = lost->util;
26         hashcpy(ui->sha1[stage - 1], ce->sha1);
27         ui->mode[stage - 1] = ce->ce_mode;
28 }
29
30 static int write_one(struct string_list_item *item, void *cbdata)
31 {
32         struct strbuf *sb = cbdata;
33         struct resolve_undo_info *ui = item->util;
34         int i;
35
36         if (!ui)
37                 return 0;
38         strbuf_addstr(sb, item->string);
39         strbuf_addch(sb, 0);
40         for (i = 0; i < 3; i++)
41                 strbuf_addf(sb, "%o%c", ui->mode[i], 0);
42         for (i = 0; i < 3; i++) {
43                 if (!ui->mode[i])
44                         continue;
45                 strbuf_add(sb, ui->sha1[i], 20);
46         }
47         return 0;
48 }
49
50 void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
51 {
52         for_each_string_list(write_one, resolve_undo, sb);
53 }
54
55 struct string_list *resolve_undo_read(void *data, unsigned long size)
56 {
57         struct string_list *resolve_undo;
58         size_t len;
59         char *endptr;
60         int i;
61
62         resolve_undo = xcalloc(1, sizeof(*resolve_undo));
63         resolve_undo->strdup_strings = 1;
64
65         while (size) {
66                 struct string_list_item *lost;
67                 struct resolve_undo_info *ui;
68
69                 len = strlen(data) + 1;
70                 if (size <= len)
71                         goto error;
72                 lost = string_list_insert(data, resolve_undo);
73                 if (!lost->util)
74                         lost->util = xcalloc(1, sizeof(*ui));
75                 ui = lost->util;
76                 size -= len;
77                 data += len;
78
79                 for (i = 0; i < 3; i++) {
80                         ui->mode[i] = strtoul(data, &endptr, 8);
81                         if (!endptr || endptr == data || *endptr)
82                                 goto error;
83                         len = (endptr + 1) - (char*)data;
84                         if (size <= len)
85                                 goto error;
86                         size -= len;
87                         data += len;
88                 }
89
90                 for (i = 0; i < 3; i++) {
91                         if (!ui->mode[i])
92                                 continue;
93                         if (size < 20)
94                                 goto error;
95                         hashcpy(ui->sha1[i], data);
96                         size -= 20;
97                         data += 20;
98                 }
99         }
100         return resolve_undo;
101
102 error:
103         string_list_clear(resolve_undo, 1);
104         error("Index records invalid resolve-undo information");
105         return NULL;
106 }
107
108 void resolve_undo_clear_index(struct index_state *istate)
109 {
110         struct string_list *resolve_undo = istate->resolve_undo;
111         if (!resolve_undo)
112                 return;
113         string_list_clear(resolve_undo, 1);
114         free(resolve_undo);
115         istate->resolve_undo = NULL;
116         istate->cache_changed = 1;
117 }