replace_object.con commit rerere: don't segfault on failure to open rr-cache (e5f5917)
   1#include "cache.h"
   2#include "sha1-lookup.h"
   3#include "refs.h"
   4
   5static struct replace_object {
   6        unsigned char sha1[2][20];
   7} **replace_object;
   8
   9static int replace_object_alloc, replace_object_nr;
  10
  11static const unsigned char *replace_sha1_access(size_t index, void *table)
  12{
  13        struct replace_object **replace = table;
  14        return replace[index]->sha1[0];
  15}
  16
  17static int replace_object_pos(const unsigned char *sha1)
  18{
  19        return sha1_pos(sha1, replace_object, replace_object_nr,
  20                        replace_sha1_access);
  21}
  22
  23static int register_replace_object(struct replace_object *replace,
  24                                   int ignore_dups)
  25{
  26        int pos = replace_object_pos(replace->sha1[0]);
  27
  28        if (0 <= pos) {
  29                if (ignore_dups)
  30                        free(replace);
  31                else {
  32                        free(replace_object[pos]);
  33                        replace_object[pos] = replace;
  34                }
  35                return 1;
  36        }
  37        pos = -pos - 1;
  38        if (replace_object_alloc <= ++replace_object_nr) {
  39                replace_object_alloc = alloc_nr(replace_object_alloc);
  40                replace_object = xrealloc(replace_object,
  41                                          sizeof(*replace_object) *
  42                                          replace_object_alloc);
  43        }
  44        if (pos < replace_object_nr)
  45                memmove(replace_object + pos + 1,
  46                        replace_object + pos,
  47                        (replace_object_nr - pos - 1) *
  48                        sizeof(*replace_object));
  49        replace_object[pos] = replace;
  50        return 0;
  51}
  52
  53static int register_replace_ref(const char *refname,
  54                                const unsigned char *sha1,
  55                                int flag, void *cb_data)
  56{
  57        /* Get sha1 from refname */
  58        const char *slash = strrchr(refname, '/');
  59        const char *hash = slash ? slash + 1 : refname;
  60        struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj));
  61
  62        if (strlen(hash) != 40 || get_sha1_hex(hash, repl_obj->sha1[0])) {
  63                free(repl_obj);
  64                warning("bad replace ref name: %s", refname);
  65                return 0;
  66        }
  67
  68        /* Copy sha1 from the read ref */
  69        hashcpy(repl_obj->sha1[1], sha1);
  70
  71        /* Register new object */
  72        if (register_replace_object(repl_obj, 1))
  73                die("duplicate replace ref: %s", refname);
  74
  75        return 0;
  76}
  77
  78static void prepare_replace_object(void)
  79{
  80        static int replace_object_prepared;
  81
  82        if (replace_object_prepared)
  83                return;
  84
  85        for_each_replace_ref(register_replace_ref, NULL);
  86        replace_object_prepared = 1;
  87}
  88
  89/* We allow "recursive" replacement. Only within reason, though */
  90#define MAXREPLACEDEPTH 5
  91
  92const unsigned char *lookup_replace_object(const unsigned char *sha1)
  93{
  94        int pos, depth = MAXREPLACEDEPTH;
  95        const unsigned char *cur = sha1;
  96
  97        if (!read_replace_refs)
  98                return sha1;
  99
 100        prepare_replace_object();
 101
 102        /* Try to recursively replace the object */
 103        do {
 104                if (--depth < 0)
 105                        die("replace depth too high for object %s",
 106                            sha1_to_hex(sha1));
 107
 108                pos = replace_object_pos(cur);
 109                if (0 <= pos)
 110                        cur = replace_object[pos]->sha1[1];
 111        } while (0 <= pos);
 112
 113        return cur;
 114}