Coverage Report

Created: 2023-02-27 06:33

/src/git/resolve-undo.c
Line
Count
Source (jump to first uncovered line)
1
#include "cache.h"
2
#include "dir.h"
3
#include "resolve-undo.h"
4
#include "string-list.h"
5
6
/* The only error case is to run out of memory in string-list */
7
void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
8
0
{
9
0
  struct string_list_item *lost;
10
0
  struct resolve_undo_info *ui;
11
0
  struct string_list *resolve_undo;
12
0
  int stage = ce_stage(ce);
13
14
0
  if (!stage)
15
0
    return;
16
17
0
  if (!istate->resolve_undo) {
18
0
    CALLOC_ARRAY(resolve_undo, 1);
19
0
    resolve_undo->strdup_strings = 1;
20
0
    istate->resolve_undo = resolve_undo;
21
0
  }
22
0
  resolve_undo = istate->resolve_undo;
23
0
  lost = string_list_insert(resolve_undo, ce->name);
24
0
  if (!lost->util)
25
0
    lost->util = xcalloc(1, sizeof(*ui));
26
0
  ui = lost->util;
27
0
  oidcpy(&ui->oid[stage - 1], &ce->oid);
28
0
  ui->mode[stage - 1] = ce->ce_mode;
29
0
}
30
31
void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
32
0
{
33
0
  struct string_list_item *item;
34
0
  for_each_string_list_item(item, resolve_undo) {
35
0
    struct resolve_undo_info *ui = item->util;
36
0
    int i;
37
38
0
    if (!ui)
39
0
      continue;
40
0
    strbuf_addstr(sb, item->string);
41
0
    strbuf_addch(sb, 0);
42
0
    for (i = 0; i < 3; i++)
43
0
      strbuf_addf(sb, "%o%c", ui->mode[i], 0);
44
0
    for (i = 0; i < 3; i++) {
45
0
      if (!ui->mode[i])
46
0
        continue;
47
0
      strbuf_add(sb, ui->oid[i].hash, the_hash_algo->rawsz);
48
0
    }
49
0
  }
50
0
}
51
52
struct string_list *resolve_undo_read(const char *data, unsigned long size)
53
0
{
54
0
  struct string_list *resolve_undo;
55
0
  size_t len;
56
0
  char *endptr;
57
0
  int i;
58
0
  const unsigned rawsz = the_hash_algo->rawsz;
59
60
0
  CALLOC_ARRAY(resolve_undo, 1);
61
0
  resolve_undo->strdup_strings = 1;
62
63
0
  while (size) {
64
0
    struct string_list_item *lost;
65
0
    struct resolve_undo_info *ui;
66
67
0
    len = strlen(data) + 1;
68
0
    if (size <= len)
69
0
      goto error;
70
0
    lost = string_list_insert(resolve_undo, data);
71
0
    if (!lost->util)
72
0
      lost->util = xcalloc(1, sizeof(*ui));
73
0
    ui = lost->util;
74
0
    size -= len;
75
0
    data += len;
76
77
0
    for (i = 0; i < 3; i++) {
78
0
      ui->mode[i] = strtoul(data, &endptr, 8);
79
0
      if (!endptr || endptr == data || *endptr)
80
0
        goto error;
81
0
      len = (endptr + 1) - (char*)data;
82
0
      if (size <= len)
83
0
        goto error;
84
0
      size -= len;
85
0
      data += len;
86
0
    }
87
88
0
    for (i = 0; i < 3; i++) {
89
0
      if (!ui->mode[i])
90
0
        continue;
91
0
      if (size < rawsz)
92
0
        goto error;
93
0
      oidread(&ui->oid[i], (const unsigned char *)data);
94
0
      size -= rawsz;
95
0
      data += rawsz;
96
0
    }
97
0
  }
98
0
  return resolve_undo;
99
100
0
error:
101
0
  string_list_clear(resolve_undo, 1);
102
0
  error("Index records invalid resolve-undo information");
103
0
  return NULL;
104
0
}
105
106
void resolve_undo_clear_index(struct index_state *istate)
107
460
{
108
460
  struct string_list *resolve_undo = istate->resolve_undo;
109
460
  if (!resolve_undo)
110
460
    return;
111
0
  string_list_clear(resolve_undo, 1);
112
0
  free(resolve_undo);
113
0
  istate->resolve_undo = NULL;
114
0
  istate->cache_changed |= RESOLVE_UNDO_CHANGED;
115
0
}
116
117
int unmerge_index_entry_at(struct index_state *istate, int pos)
118
0
{
119
0
  const struct cache_entry *ce;
120
0
  struct string_list_item *item;
121
0
  struct resolve_undo_info *ru;
122
0
  int i, err = 0, matched;
123
0
  char *name;
124
125
0
  if (!istate->resolve_undo)
126
0
    return pos;
127
128
0
  ce = istate->cache[pos];
129
0
  if (ce_stage(ce)) {
130
    /* already unmerged */
131
0
    while ((pos < istate->cache_nr) &&
132
0
           ! strcmp(istate->cache[pos]->name, ce->name))
133
0
      pos++;
134
0
    return pos - 1; /* return the last entry processed */
135
0
  }
136
0
  item = string_list_lookup(istate->resolve_undo, ce->name);
137
0
  if (!item)
138
0
    return pos;
139
0
  ru = item->util;
140
0
  if (!ru)
141
0
    return pos;
142
0
  matched = ce->ce_flags & CE_MATCHED;
143
0
  name = xstrdup(ce->name);
144
0
  remove_index_entry_at(istate, pos);
145
0
  for (i = 0; i < 3; i++) {
146
0
    struct cache_entry *nce;
147
0
    if (!ru->mode[i])
148
0
      continue;
149
0
    nce = make_cache_entry(istate,
150
0
               ru->mode[i],
151
0
               &ru->oid[i],
152
0
               name, i + 1, 0);
153
0
    if (matched)
154
0
      nce->ce_flags |= CE_MATCHED;
155
0
    if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
156
0
      err = 1;
157
0
      error("cannot unmerge '%s'", name);
158
0
    }
159
0
  }
160
0
  free(name);
161
0
  if (err)
162
0
    return pos;
163
0
  free(ru);
164
0
  item->util = NULL;
165
0
  return unmerge_index_entry_at(istate, pos);
166
0
}
167
168
void unmerge_marked_index(struct index_state *istate)
169
0
{
170
0
  int i;
171
172
0
  if (!istate->resolve_undo)
173
0
    return;
174
175
  /* TODO: audit for interaction with sparse-index. */
176
0
  ensure_full_index(istate);
177
0
  for (i = 0; i < istate->cache_nr; i++) {
178
0
    const struct cache_entry *ce = istate->cache[i];
179
0
    if (ce->ce_flags & CE_MATCHED)
180
0
      i = unmerge_index_entry_at(istate, i);
181
0
  }
182
0
}
183
184
void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
185
0
{
186
0
  int i;
187
188
0
  if (!istate->resolve_undo)
189
0
    return;
190
191
  /* TODO: audit for interaction with sparse-index. */
192
0
  ensure_full_index(istate);
193
0
  for (i = 0; i < istate->cache_nr; i++) {
194
0
    const struct cache_entry *ce = istate->cache[i];
195
0
    if (!ce_path_match(istate, ce, pathspec, NULL))
196
0
      continue;
197
0
    i = unmerge_index_entry_at(istate, i);
198
0
  }
199
0
}