resolve-undo.con commit test-lib: Allow overriding of TEST_DIRECTORY (62f5390)
   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 */
   7void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
   8{
   9        struct string_list_item *lost;
  10        struct resolve_undo_info *ui;
  11        struct string_list *resolve_undo;
  12        int stage = ce_stage(ce);
  13
  14        if (!stage)
  15                return;
  16
  17        if (!istate->resolve_undo) {
  18                resolve_undo = xcalloc(1, sizeof(*resolve_undo));
  19                resolve_undo->strdup_strings = 1;
  20                istate->resolve_undo = resolve_undo;
  21        }
  22        resolve_undo = istate->resolve_undo;
  23        lost = string_list_insert(resolve_undo, ce->name);
  24        if (!lost->util)
  25                lost->util = xcalloc(1, sizeof(*ui));
  26        ui = lost->util;
  27        hashcpy(ui->sha1[stage - 1], ce->sha1);
  28        ui->mode[stage - 1] = ce->ce_mode;
  29}
  30
  31static int write_one(struct string_list_item *item, void *cbdata)
  32{
  33        struct strbuf *sb = cbdata;
  34        struct resolve_undo_info *ui = item->util;
  35        int i;
  36
  37        if (!ui)
  38                return 0;
  39        strbuf_addstr(sb, item->string);
  40        strbuf_addch(sb, 0);
  41        for (i = 0; i < 3; i++)
  42                strbuf_addf(sb, "%o%c", ui->mode[i], 0);
  43        for (i = 0; i < 3; i++) {
  44                if (!ui->mode[i])
  45                        continue;
  46                strbuf_add(sb, ui->sha1[i], 20);
  47        }
  48        return 0;
  49}
  50
  51void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
  52{
  53   for_each_string_list(resolve_undo, write_one, sb);
  54}
  55
  56struct string_list *resolve_undo_read(const char *data, unsigned long size)
  57{
  58        struct string_list *resolve_undo;
  59        size_t len;
  60        char *endptr;
  61        int i;
  62
  63        resolve_undo = xcalloc(1, sizeof(*resolve_undo));
  64        resolve_undo->strdup_strings = 1;
  65
  66        while (size) {
  67                struct string_list_item *lost;
  68                struct resolve_undo_info *ui;
  69
  70                len = strlen(data) + 1;
  71                if (size <= len)
  72                        goto error;
  73                lost = string_list_insert(resolve_undo, data);
  74                if (!lost->util)
  75                        lost->util = xcalloc(1, sizeof(*ui));
  76                ui = lost->util;
  77                size -= len;
  78                data += len;
  79
  80                for (i = 0; i < 3; i++) {
  81                        ui->mode[i] = strtoul(data, &endptr, 8);
  82                        if (!endptr || endptr == data || *endptr)
  83                                goto error;
  84                        len = (endptr + 1) - (char*)data;
  85                        if (size <= len)
  86                                goto error;
  87                        size -= len;
  88                        data += len;
  89                }
  90
  91                for (i = 0; i < 3; i++) {
  92                        if (!ui->mode[i])
  93                                continue;
  94                        if (size < 20)
  95                                goto error;
  96                        hashcpy(ui->sha1[i], (const unsigned char *)data);
  97                        size -= 20;
  98                        data += 20;
  99                }
 100        }
 101        return resolve_undo;
 102
 103error:
 104        string_list_clear(resolve_undo, 1);
 105        error("Index records invalid resolve-undo information");
 106        return NULL;
 107}
 108
 109void resolve_undo_clear_index(struct index_state *istate)
 110{
 111        struct string_list *resolve_undo = istate->resolve_undo;
 112        if (!resolve_undo)
 113                return;
 114        string_list_clear(resolve_undo, 1);
 115        free(resolve_undo);
 116        istate->resolve_undo = NULL;
 117        istate->cache_changed = 1;
 118}
 119
 120int unmerge_index_entry_at(struct index_state *istate, int pos)
 121{
 122        struct cache_entry *ce;
 123        struct string_list_item *item;
 124        struct resolve_undo_info *ru;
 125        int i, err = 0;
 126
 127        if (!istate->resolve_undo)
 128                return pos;
 129
 130        ce = istate->cache[pos];
 131        if (ce_stage(ce)) {
 132                /* already unmerged */
 133                while ((pos < istate->cache_nr) &&
 134                       ! strcmp(istate->cache[pos]->name, ce->name))
 135                        pos++;
 136                return pos - 1; /* return the last entry processed */
 137        }
 138        item = string_list_lookup(istate->resolve_undo, ce->name);
 139        if (!item)
 140                return pos;
 141        ru = item->util;
 142        if (!ru)
 143                return pos;
 144        remove_index_entry_at(istate, pos);
 145        for (i = 0; i < 3; i++) {
 146                struct cache_entry *nce;
 147                if (!ru->mode[i])
 148                        continue;
 149                nce = make_cache_entry(ru->mode[i], ru->sha1[i],
 150                                       ce->name, i + 1, 0);
 151                if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
 152                        err = 1;
 153                        error("cannot unmerge '%s'", ce->name);
 154                }
 155        }
 156        if (err)
 157                return pos;
 158        free(ru);
 159        item->util = NULL;
 160        return unmerge_index_entry_at(istate, pos);
 161}
 162
 163void unmerge_index(struct index_state *istate, const char **pathspec)
 164{
 165        int i;
 166
 167        if (!istate->resolve_undo)
 168                return;
 169
 170        for (i = 0; i < istate->cache_nr; i++) {
 171                struct cache_entry *ce = istate->cache[i];
 172                if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))
 173                        continue;
 174                i = unmerge_index_entry_at(istate, i);
 175        }
 176}