fsck-cache.con commit Make fsck-cache start parsing the object types, and checking their (1ea34e3)
   1#include "cache.h"
   2
   3#include <sys/types.h>
   4#include <dirent.h>
   5
   6/*
   7 * These two functions should build up a graph in memory about
   8 * what objects we've referenced, and found, and types..
   9 *
  10 * Right now we don't do that kind of reachability checking. Yet.
  11 */
  12static void mark_needs_sha1(unsigned char *parent, const char * type, unsigned char *child)
  13{
  14}
  15
  16static int mark_sha1_seen(unsigned char *sha1, char *tag)
  17{
  18        return 0;
  19}
  20
  21static int fsck_tree(unsigned char *sha1, void *data, unsigned long size)
  22{
  23        while (size) {
  24                int len = 1+strlen(data);
  25                unsigned char *file_sha1 = data + len;
  26                char *path = strchr(data, ' ');
  27                if (size < len + 20 || !path)
  28                        return -1;
  29                data += len + 20;
  30                size -= len + 20;
  31                mark_needs_sha1(sha1, "blob", file_sha1);
  32        }
  33}
  34
  35static int fsck_commit(unsigned char *sha1, void *data, unsigned long size)
  36{
  37        unsigned char tree_sha1[20];
  38        unsigned char parent_sha1[20];
  39
  40        if (memcmp(data, "tree ", 5))
  41                return -1;
  42        if (get_sha1_hex(data + 5, tree_sha1) < 0)
  43                return -1;
  44        mark_needs_sha1(sha1, "tree", tree_sha1);
  45        data += 5 + 40 + 1;     /* "tree " + <hex sha1> + '\n' */
  46        while (!memcmp(data, "parent ", 7)) {
  47                if (get_sha1_hex(data + 7, parent_sha1) < 0)
  48                        return -1;
  49                mark_needs_sha1(sha1, "commit", parent_sha1);
  50                data += 7 + 40 + 1;     /* "parent " + <hex sha1> + '\n' */
  51        }
  52}
  53
  54static int fsck_entry(unsigned char *sha1, char *tag, void *data, unsigned long size)
  55{
  56        if (!strcmp(tag, "blob")) {
  57                /* Nothing to check */;
  58        } else if (!strcmp(tag, "tree")) {
  59                if (fsck_tree(sha1, data, size) < 0)
  60                        return -1;
  61        } else if (!strcmp(tag, "commit")) {
  62                if (fsck_commit(sha1, data, size) < 0)
  63                        return -1;
  64        } else
  65                return -1;
  66        return mark_sha1_seen(sha1, tag);
  67}
  68
  69static int fsck_name(char *hex)
  70{
  71        unsigned char sha1[20];
  72        if (!get_sha1_hex(hex, sha1)) {
  73                unsigned long mapsize;
  74                void *map = map_sha1_file(sha1, &mapsize);
  75                if (map) {
  76                        char type[100];
  77                        unsigned long size;
  78                        void *buffer = NULL;
  79                        if (!check_sha1_signature(sha1, map, mapsize))
  80                                buffer = unpack_sha1_file(map, mapsize, type, &size);
  81                        munmap(map, mapsize);
  82                        if (buffer && !fsck_entry(sha1, type, buffer, size))
  83                                return 0;
  84                }
  85        }
  86        return -1;
  87}
  88
  89static int fsck_dir(int i, char *path)
  90{
  91        DIR *dir = opendir(path);
  92        struct dirent *de;
  93
  94        if (!dir) {
  95                fprintf(stderr, "missing sha1 directory '%s'", path);
  96                return -1;
  97        }
  98
  99        while ((de = readdir(dir)) != NULL) {
 100                char name[100];
 101                int len = strlen(de->d_name);
 102
 103                switch (len) {
 104                case 2:
 105                        if (de->d_name[1] != '.')
 106                                break;
 107                case 1:
 108                        if (de->d_name[0] != '.')
 109                                break;
 110                        continue;
 111                case 38:
 112                        sprintf(name, "%02x", i);
 113                        memcpy(name+2, de->d_name, len+1);
 114                        if (!fsck_name(name))
 115                                continue;
 116                }
 117                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
 118        }
 119        closedir(dir);
 120        return 0;
 121}
 122
 123int main(int argc, char **argv)
 124{
 125        int i;
 126        char *sha1_dir;
 127
 128        if (argc != 1)
 129                usage("fsck-cache");
 130        sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
 131        for (i = 0; i < 256; i++) {
 132                static char dir[4096];
 133                sprintf(dir, "%s/%02x", sha1_dir, i);
 134                fsck_dir(i, dir);
 135        }
 136        return 0;
 137}