resolve-undo.con commit Merge branch 'dl/use-sq-from-test-lib' (d693345)
   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        oidcpy(&ui->oid[stage - 1], &ce->oid);
  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->oid[i].hash, the_hash_algo->rawsz);
  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        const unsigned rawsz = the_hash_algo->rawsz;
  59
  60        resolve_undo = xcalloc(1, sizeof(*resolve_undo));
  61        resolve_undo->strdup_strings = 1;
  62
  63        while (size) {
  64                struct string_list_item *lost;
  65                struct resolve_undo_info *ui;
  66
  67                len = strlen(data) + 1;
  68                if (size <= len)
  69                        goto error;
  70                lost = string_list_insert(resolve_undo, data);
  71                if (!lost->util)
  72                        lost->util = xcalloc(1, sizeof(*ui));
  73                ui = lost->util;
  74                size -= len;
  75                data += len;
  76
  77                for (i = 0; i < 3; i++) {
  78                        ui->mode[i] = strtoul(data, &endptr, 8);
  79                        if (!endptr || endptr == data || *endptr)
  80                                goto error;
  81                        len = (endptr + 1) - (char*)data;
  82                        if (size <= len)
  83                                goto error;
  84                        size -= len;
  85                        data += len;
  86                }
  87
  88                for (i = 0; i < 3; i++) {
  89                        if (!ui->mode[i])
  90                                continue;
  91                        if (size < rawsz)
  92                                goto error;
  93                        oidread(&ui->oid[i], (const unsigned char *)data);
  94                        size -= rawsz;
  95                        data += rawsz;
  96                }
  97        }
  98        return resolve_undo;
  99
 100error:
 101        string_list_clear(resolve_undo, 1);
 102        error("Index records invalid resolve-undo information");
 103        return NULL;
 104}
 105
 106void resolve_undo_clear_index(struct index_state *istate)
 107{
 108        struct string_list *resolve_undo = istate->resolve_undo;
 109        if (!resolve_undo)
 110                return;
 111        string_list_clear(resolve_undo, 1);
 112        free(resolve_undo);
 113        istate->resolve_undo = NULL;
 114        istate->cache_changed |= RESOLVE_UNDO_CHANGED;
 115}
 116
 117int unmerge_index_entry_at(struct index_state *istate, int pos)
 118{
 119        const struct cache_entry *ce;
 120        struct string_list_item *item;
 121        struct resolve_undo_info *ru;
 122        int i, err = 0, matched;
 123        char *name;
 124
 125        if (!istate->resolve_undo)
 126                return pos;
 127
 128        ce = istate->cache[pos];
 129        if (ce_stage(ce)) {
 130                /* already unmerged */
 131                while ((pos < istate->cache_nr) &&
 132                       ! strcmp(istate->cache[pos]->name, ce->name))
 133                        pos++;
 134                return pos - 1; /* return the last entry processed */
 135        }
 136        item = string_list_lookup(istate->resolve_undo, ce->name);
 137        if (!item)
 138                return pos;
 139        ru = item->util;
 140        if (!ru)
 141                return pos;
 142        matched = ce->ce_flags & CE_MATCHED;
 143        name = xstrdup(ce->name);
 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(istate,
 150                                       ru->mode[i],
 151                                       &ru->oid[i],
 152                                       name, i + 1, 0);
 153                if (matched)
 154                        nce->ce_flags |= CE_MATCHED;
 155                if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
 156                        err = 1;
 157                        error("cannot unmerge '%s'", name);
 158                }
 159        }
 160        free(name);
 161        if (err)
 162                return pos;
 163        free(ru);
 164        item->util = NULL;
 165        return unmerge_index_entry_at(istate, pos);
 166}
 167
 168void unmerge_marked_index(struct index_state *istate)
 169{
 170        int i;
 171
 172        if (!istate->resolve_undo)
 173                return;
 174
 175        for (i = 0; i < istate->cache_nr; i++) {
 176                const struct cache_entry *ce = istate->cache[i];
 177                if (ce->ce_flags & CE_MATCHED)
 178                        i = unmerge_index_entry_at(istate, i);
 179        }
 180}
 181
 182void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
 183{
 184        int i;
 185
 186        if (!istate->resolve_undo)
 187                return;
 188
 189        for (i = 0; i < istate->cache_nr; i++) {
 190                const struct cache_entry *ce = istate->cache[i];
 191                if (!ce_path_match(istate, ce, pathspec, NULL))
 192                        continue;
 193                i = unmerge_index_entry_at(istate, i);
 194        }
 195}