tree-walk.con commit Merge branch 'jc/lt-tree-n-cache-tree' into next (52bc0e2)
   1#include "cache.h"
   2#include "tree-walk.h"
   3#include "tree.h"
   4
   5void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
   6{
   7        unsigned long size = 0;
   8        void *buf = NULL;
   9
  10        if (sha1) {
  11                buf = read_object_with_reference(sha1, tree_type, &size, NULL);
  12                if (!buf)
  13                        die("unable to read tree %s", sha1_to_hex(sha1));
  14        }
  15        desc->size = size;
  16        desc->buf = buf;
  17        return buf;
  18}
  19
  20static int entry_compare(struct name_entry *a, struct name_entry *b)
  21{
  22        return base_name_compare(
  23                        a->path, a->pathlen, a->mode,
  24                        b->path, b->pathlen, b->mode);
  25}
  26
  27static void entry_clear(struct name_entry *a)
  28{
  29        memset(a, 0, sizeof(*a));
  30}
  31
  32static void entry_extract(struct tree_desc *t, struct name_entry *a)
  33{
  34        a->sha1 = tree_entry_extract(t, &a->path, &a->mode);
  35        a->pathlen = strlen(a->path);
  36}
  37
  38void update_tree_entry(struct tree_desc *desc)
  39{
  40        void *buf = desc->buf;
  41        unsigned long size = desc->size;
  42        int len = strlen(buf) + 1 + 20;
  43
  44        if (size < len)
  45                die("corrupt tree file");
  46        desc->buf = buf + len;
  47        desc->size = size - len;
  48}
  49
  50static const char *get_mode(const char *str, unsigned int *modep)
  51{
  52        unsigned char c;
  53        unsigned int mode = 0;
  54
  55        while ((c = *str++) != ' ') {
  56                if (c < '0' || c > '7')
  57                        return NULL;
  58                mode = (mode << 3) + (c - '0');
  59        }
  60        *modep = mode;
  61        return str;
  62}
  63
  64const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned int *modep)
  65{
  66        void *tree = desc->buf;
  67        unsigned long size = desc->size;
  68        int len = strlen(tree)+1;
  69        const unsigned char *sha1 = tree + len;
  70        const char *path;
  71        unsigned int mode;
  72
  73        path = get_mode(tree, &mode);
  74        if (!path || size < len + 20)
  75                die("corrupt tree file");
  76        *pathp = path;
  77        *modep = canon_mode(mode);
  78        return sha1;
  79}
  80
  81void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback)
  82{
  83        struct name_entry *entry = xmalloc(n*sizeof(*entry));
  84
  85        for (;;) {
  86                struct name_entry entry[3];
  87                unsigned long mask = 0;
  88                int i, last;
  89
  90                last = -1;
  91                for (i = 0; i < n; i++) {
  92                        if (!t[i].size)
  93                                continue;
  94                        entry_extract(t+i, entry+i);
  95                        if (last >= 0) {
  96                                int cmp = entry_compare(entry+i, entry+last);
  97
  98                                /*
  99                                 * Is the new name bigger than the old one?
 100                                 * Ignore it
 101                                 */
 102                                if (cmp > 0)
 103                                        continue;
 104                                /*
 105                                 * Is the new name smaller than the old one?
 106                                 * Ignore all old ones
 107                                 */
 108                                if (cmp < 0)
 109                                        mask = 0;
 110                        }
 111                        mask |= 1ul << i;
 112                        last = i;
 113                }
 114                if (!mask)
 115                        break;
 116
 117                /*
 118                 * Update the tree entries we've walked, and clear
 119                 * all the unused name-entries.
 120                 */
 121                for (i = 0; i < n; i++) {
 122                        if (mask & (1ul << i)) {
 123                                update_tree_entry(t+i);
 124                                continue;
 125                        }
 126                        entry_clear(entry + i);
 127                }
 128                callback(n, mask, entry, base);
 129        }
 130        free(entry);
 131}
 132
 133static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)
 134{
 135        int namelen = strlen(name);
 136        while (t->size) {
 137                const char *entry;
 138                const unsigned char *sha1;
 139                int entrylen, cmp;
 140
 141                sha1 = tree_entry_extract(t, &entry, mode);
 142                update_tree_entry(t);
 143                entrylen = strlen(entry);
 144                if (entrylen > namelen)
 145                        continue;
 146                cmp = memcmp(name, entry, entrylen);
 147                if (cmp > 0)
 148                        continue;
 149                if (cmp < 0)
 150                        break;
 151                if (entrylen == namelen) {
 152                        memcpy(result, sha1, 20);
 153                        return 0;
 154                }
 155                if (name[entrylen] != '/')
 156                        continue;
 157                if (!S_ISDIR(*mode))
 158                        break;
 159                if (++entrylen == namelen) {
 160                        memcpy(result, sha1, 20);
 161                        return 0;
 162                }
 163                return get_tree_entry(sha1, name + entrylen, result, mode);
 164        }
 165        return -1;
 166}
 167
 168int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode)
 169{
 170        int retval;
 171        void *tree;
 172        struct tree_desc t;
 173
 174        tree = read_object_with_reference(tree_sha1, tree_type, &t.size, NULL);
 175        if (!tree)
 176                return -1;
 177        t.buf = tree;
 178        retval = find_tree_entry(&t, name, sha1, mode);
 179        free(tree);
 180        return retval;
 181}
 182