Coverage Report

Created: 2024-09-16 06:10

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