resolve-undo.c 4.31 KB
Newer Older
1
#include "cache.h"
2
#include "dir.h"
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include "resolve-undo.h"
#include "string-list.h"

/* The only error case is to run out of memory in string-list */
void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
{
	struct string_list_item *lost;
	struct resolve_undo_info *ui;
	struct string_list *resolve_undo;
	int stage = ce_stage(ce);

	if (!stage)
		return;

	if (!istate->resolve_undo) {
		resolve_undo = xcalloc(1, sizeof(*resolve_undo));
		resolve_undo->strdup_strings = 1;
		istate->resolve_undo = resolve_undo;
	}
	resolve_undo = istate->resolve_undo;
23
	lost = string_list_insert(resolve_undo, ce->name);
24 25 26 27 28 29 30
	if (!lost->util)
		lost->util = xcalloc(1, sizeof(*ui));
	ui = lost->util;
	hashcpy(ui->sha1[stage - 1], ce->sha1);
	ui->mode[stage - 1] = ce->ce_mode;
}

31
void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
32
{
33 34 35 36
	struct string_list_item *item;
	for_each_string_list_item(item, resolve_undo) {
		struct resolve_undo_info *ui = item->util;
		int i;
37

38
		if (!ui)
39
			continue;
40 41 42 43 44 45 46 47 48
		strbuf_addstr(sb, item->string);
		strbuf_addch(sb, 0);
		for (i = 0; i < 3; i++)
			strbuf_addf(sb, "%o%c", ui->mode[i], 0);
		for (i = 0; i < 3; i++) {
			if (!ui->mode[i])
				continue;
			strbuf_add(sb, ui->sha1[i], 20);
		}
49 50 51
	}
}

52
struct string_list *resolve_undo_read(const char *data, unsigned long size)
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
{
	struct string_list *resolve_undo;
	size_t len;
	char *endptr;
	int i;

	resolve_undo = xcalloc(1, sizeof(*resolve_undo));
	resolve_undo->strdup_strings = 1;

	while (size) {
		struct string_list_item *lost;
		struct resolve_undo_info *ui;

		len = strlen(data) + 1;
		if (size <= len)
			goto error;
69
		lost = string_list_insert(resolve_undo, data);
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
		if (!lost->util)
			lost->util = xcalloc(1, sizeof(*ui));
		ui = lost->util;
		size -= len;
		data += len;

		for (i = 0; i < 3; i++) {
			ui->mode[i] = strtoul(data, &endptr, 8);
			if (!endptr || endptr == data || *endptr)
				goto error;
			len = (endptr + 1) - (char*)data;
			if (size <= len)
				goto error;
			size -= len;
			data += len;
		}

		for (i = 0; i < 3; i++) {
			if (!ui->mode[i])
				continue;
			if (size < 20)
				goto error;
92
			hashcpy(ui->sha1[i], (const unsigned char *)data);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
			size -= 20;
			data += 20;
		}
	}
	return resolve_undo;

error:
	string_list_clear(resolve_undo, 1);
	error("Index records invalid resolve-undo information");
	return NULL;
}

void resolve_undo_clear_index(struct index_state *istate)
{
	struct string_list *resolve_undo = istate->resolve_undo;
	if (!resolve_undo)
		return;
	string_list_clear(resolve_undo, 1);
	free(resolve_undo);
	istate->resolve_undo = NULL;
113
	istate->cache_changed |= RESOLVE_UNDO_CHANGED;
114
}
115 116 117

int unmerge_index_entry_at(struct index_state *istate, int pos)
{
118
	const struct cache_entry *ce;
119 120
	struct string_list_item *item;
	struct resolve_undo_info *ru;
121
	int i, err = 0, matched;
122
	char *name;
123 124 125 126 127 128 129 130 131 132 133 134

	if (!istate->resolve_undo)
		return pos;

	ce = istate->cache[pos];
	if (ce_stage(ce)) {
		/* already unmerged */
		while ((pos < istate->cache_nr) &&
		       ! strcmp(istate->cache[pos]->name, ce->name))
			pos++;
		return pos - 1; /* return the last entry processed */
	}
135
	item = string_list_lookup(istate->resolve_undo, ce->name);
136 137 138 139 140
	if (!item)
		return pos;
	ru = item->util;
	if (!ru)
		return pos;
141
	matched = ce->ce_flags & CE_MATCHED;
142
	name = xstrdup(ce->name);
143 144 145 146 147 148
	remove_index_entry_at(istate, pos);
	for (i = 0; i < 3; i++) {
		struct cache_entry *nce;
		if (!ru->mode[i])
			continue;
		nce = make_cache_entry(ru->mode[i], ru->sha1[i],
149
				       name, i + 1, 0);
150 151
		if (matched)
			nce->ce_flags |= CE_MATCHED;
152 153
		if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
			err = 1;
154
			error("cannot unmerge '%s'", name);
155 156
		}
	}
157
	free(name);
158 159 160 161 162 163 164
	if (err)
		return pos;
	free(ru);
	item->util = NULL;
	return unmerge_index_entry_at(istate, pos);
}

165 166 167 168 169 170 171 172
void unmerge_marked_index(struct index_state *istate)
{
	int i;

	if (!istate->resolve_undo)
		return;

	for (i = 0; i < istate->cache_nr; i++) {
173
		const struct cache_entry *ce = istate->cache[i];
174 175 176 177 178
		if (ce->ce_flags & CE_MATCHED)
			i = unmerge_index_entry_at(istate, i);
	}
}

179
void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
180 181 182 183 184 185 186
{
	int i;

	if (!istate->resolve_undo)
		return;

	for (i = 0; i < istate->cache_nr; i++) {
187
		const struct cache_entry *ce = istate->cache[i];
188
		if (!ce_path_match(ce, pathspec, NULL))
189 190 191 192
			continue;
		i = unmerge_index_entry_at(istate, i);
	}
}