fsck-cache.con commit Allow writing to the private index file mapping. (520fc24)
   1#include "cache.h"
   2
   3#include <sys/types.h>
   4#include <dirent.h>
   5
   6#include "commit.h"
   7#include "tree.h"
   8#include "blob.h"
   9
  10#define REACHABLE 0x0001
  11
  12static int show_root = 0;
  13static int show_tags = 0;
  14static int show_unreachable = 0;
  15static unsigned char head_sha1[20];
  16
  17static void check_connectivity(void)
  18{
  19        int i;
  20
  21        /* Look up all the requirements, warn about missing objects.. */
  22        for (i = 0; i < nr_objs; i++) {
  23                struct object *obj = objs[i];
  24
  25                if (show_unreachable && !(obj->flags & REACHABLE)) {
  26                        printf("unreachable %s %s\n", obj->type, sha1_to_hex(obj->sha1));
  27                        continue;
  28                }
  29
  30                if (!obj->parsed) {
  31                        printf("missing %s %s\n", obj->type, 
  32                               sha1_to_hex(obj->sha1));
  33                }
  34                if (!obj->used) {
  35                        printf("dangling %s %s\n", obj->type, 
  36                               sha1_to_hex(obj->sha1));
  37                }
  38        }
  39}
  40
  41static int fsck_tree(unsigned char *sha1, void *data, unsigned long size)
  42{
  43        struct tree *item = lookup_tree(sha1);
  44        if (parse_tree(item))
  45                return -1;
  46        if (item->has_full_path) {
  47                fprintf(stderr, "warning: fsck-cache: tree %s "
  48                        "has full pathnames in it\n", sha1_to_hex(sha1));
  49        }
  50        return 0;
  51}
  52
  53static int fsck_commit(unsigned char *sha1, void *data, unsigned long size)
  54{
  55        struct commit *commit = lookup_commit(sha1);
  56        if (parse_commit(commit))
  57                return -1;
  58        if (!commit->tree)
  59                return -1;
  60        if (!commit->parents && show_root)
  61                printf("root %s\n", sha1_to_hex(sha1));
  62        if (!commit->date)
  63                printf("bad commit date in %s\n", sha1_to_hex(sha1));
  64        return 0;
  65}
  66
  67static int fsck_blob(unsigned char *sha1, void *data, unsigned long size)
  68{
  69        struct blob *blob = lookup_blob(sha1);
  70        blob->object.parsed = 1;
  71        return 0;
  72}
  73
  74static int fsck_tag(unsigned char *sha1, void *data, unsigned long size)
  75{
  76        int typelen, taglen;
  77        unsigned char object[20];
  78        char object_hex[60];
  79        const char *type_line, *tag_line, *sig_line;
  80
  81        if (size < 64)
  82                return -1;
  83        if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object))
  84                return -1;
  85
  86        type_line = data + 48;
  87        if (memcmp("\ntype ", type_line-1, 6))
  88                return -1;
  89
  90        tag_line = strchr(type_line, '\n');
  91        if (!tag_line || memcmp("tag ", ++tag_line, 4))
  92                return -1;
  93
  94        sig_line = strchr(tag_line, '\n');
  95        if (!sig_line)
  96                return -1;
  97        sig_line++;
  98
  99        typelen = tag_line - type_line - strlen("type \n");
 100        if (typelen >= 20)
 101                return -1;
 102        taglen = sig_line - tag_line - strlen("tag \n");
 103
 104        if (!show_tags)
 105                return 0;
 106
 107        strcpy(object_hex, sha1_to_hex(object));
 108        printf("tagged %.*s %s (%.*s) in %s\n",
 109                typelen, type_line + 5,
 110                object_hex,
 111                taglen, tag_line + 4,
 112                sha1_to_hex(sha1));
 113        return 0;
 114}
 115
 116static int fsck_entry(unsigned char *sha1, char *tag, void *data, 
 117                      unsigned long size)
 118{
 119        if (!strcmp(tag, "blob")) {
 120                if (fsck_blob(sha1, data, size) < 0)
 121                        return -1;
 122        } else if (!strcmp(tag, "tree")) {
 123                if (fsck_tree(sha1, data, size) < 0)
 124                        return -1;
 125        } else if (!strcmp(tag, "commit")) {
 126                if (fsck_commit(sha1, data, size) < 0)
 127                        return -1;
 128        } else if (!strcmp(tag, "tag")) {
 129                if (fsck_tag(sha1, data, size) < 0)
 130                        return -1;
 131        } else
 132                return -1;
 133        return 0;
 134}
 135
 136static int fsck_name(char *hex)
 137{
 138        unsigned char sha1[20];
 139        if (!get_sha1_hex(hex, sha1)) {
 140                unsigned long mapsize;
 141                void *map = map_sha1_file(sha1, &mapsize);
 142                if (map) {
 143                        char type[100];
 144                        unsigned long size;
 145                        void *buffer = unpack_sha1_file(map, mapsize, type, &size);
 146                        if (!buffer)
 147                                return -1;
 148                        if (check_sha1_signature(sha1, buffer, size, type) < 0)
 149                                printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
 150                        munmap(map, mapsize);
 151                        if (!fsck_entry(sha1, type, buffer, size))
 152                                return 0;
 153                }
 154        }
 155        return -1;
 156}
 157
 158static int fsck_dir(int i, char *path)
 159{
 160        DIR *dir = opendir(path);
 161        struct dirent *de;
 162
 163        if (!dir) {
 164                return error("missing sha1 directory '%s'", path);
 165        }
 166
 167        while ((de = readdir(dir)) != NULL) {
 168                char name[100];
 169                int len = strlen(de->d_name);
 170
 171                switch (len) {
 172                case 2:
 173                        if (de->d_name[1] != '.')
 174                                break;
 175                case 1:
 176                        if (de->d_name[0] != '.')
 177                                break;
 178                        continue;
 179                case 38:
 180                        sprintf(name, "%02x", i);
 181                        memcpy(name+2, de->d_name, len+1);
 182                        if (!fsck_name(name))
 183                                continue;
 184                }
 185                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
 186        }
 187        closedir(dir);
 188        return 0;
 189}
 190
 191int main(int argc, char **argv)
 192{
 193        int i, heads;
 194        char *sha1_dir;
 195
 196        for (i = 1; i < argc; i++) {
 197                const char *arg = argv[i];
 198
 199                if (!strcmp(arg, "--unreachable")) {
 200                        show_unreachable = 1;
 201                        continue;
 202                }
 203                if (!strcmp(arg, "--tags")) {
 204                        show_tags = 1;
 205                        continue;
 206                }
 207                if (!strcmp(arg, "--root")) {
 208                        show_root = 1;
 209                        continue;
 210                }
 211                if (*arg == '-')
 212                        usage("fsck-cache [--tags] [[--unreachable] <head-sha1>*]");
 213        }
 214
 215        sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
 216        for (i = 0; i < 256; i++) {
 217                static char dir[4096];
 218                sprintf(dir, "%s/%02x", sha1_dir, i);
 219                fsck_dir(i, dir);
 220        }
 221
 222        heads = 0;
 223        for (i = 1; i < argc; i++) {
 224                const char *arg = argv[i]; 
 225
 226                if (*arg == '-')
 227                        continue;
 228
 229                if (!get_sha1_hex(arg, head_sha1)) {
 230                        struct object *obj = &lookup_commit(head_sha1)->object;
 231                        obj->used = 1;
 232                        mark_reachable(obj, REACHABLE);
 233                        heads++;
 234                        continue;
 235                }
 236                error("expected sha1, got %s", arg);
 237        }
 238
 239        if (!heads) {
 240                if (show_unreachable) {
 241                        fprintf(stderr, "unable to do reachability without a head\n");
 242                        show_unreachable = 0; 
 243                }
 244                fprintf(stderr, "expect dangling commits - potential heads - due to lack of head information\n");
 245        }
 246
 247        check_connectivity();
 248        return 0;
 249}