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