1706c8bd818e965c21719d6083461e64e3b78377
   1/*
   2 * Builtin "git count-objects".
   3 *
   4 * Copyright (c) 2006 Junio C Hamano
   5 */
   6
   7#include "cache.h"
   8#include "dir.h"
   9#include "builtin.h"
  10#include "parse-options.h"
  11
  12static unsigned long garbage;
  13
  14static void real_report_garbage(const char *desc, const char *path)
  15{
  16        warning("%s: %s", desc, path);
  17        garbage++;
  18}
  19
  20static void count_objects(DIR *d, char *path, int len, int verbose,
  21                          unsigned long *loose,
  22                          off_t *loose_size,
  23                          unsigned long *packed_loose,
  24                          unsigned long *garbage)
  25{
  26        struct dirent *ent;
  27        while ((ent = readdir(d)) != NULL) {
  28                char hex[41];
  29                unsigned char sha1[20];
  30                const char *cp;
  31                int bad = 0;
  32
  33                if (is_dot_or_dotdot(ent->d_name))
  34                        continue;
  35                for (cp = ent->d_name; *cp; cp++) {
  36                        int ch = *cp;
  37                        if (('0' <= ch && ch <= '9') ||
  38                            ('a' <= ch && ch <= 'f'))
  39                                continue;
  40                        bad = 1;
  41                        break;
  42                }
  43                if (cp - ent->d_name != 38)
  44                        bad = 1;
  45                else {
  46                        struct stat st;
  47                        memcpy(path + len + 3, ent->d_name, 38);
  48                        path[len + 2] = '/';
  49                        path[len + 41] = 0;
  50                        if (lstat(path, &st) || !S_ISREG(st.st_mode))
  51                                bad = 1;
  52                        else
  53                                (*loose_size) += xsize_t(on_disk_bytes(st));
  54                }
  55                if (bad) {
  56                        if (verbose) {
  57                                error("garbage found: %.*s/%s",
  58                                      len + 2, path, ent->d_name);
  59                                (*garbage)++;
  60                        }
  61                        continue;
  62                }
  63                (*loose)++;
  64                if (!verbose)
  65                        continue;
  66                memcpy(hex, path+len, 2);
  67                memcpy(hex+2, ent->d_name, 38);
  68                hex[40] = 0;
  69                if (get_sha1_hex(hex, sha1))
  70                        die("internal error");
  71                if (has_sha1_pack(sha1))
  72                        (*packed_loose)++;
  73        }
  74}
  75
  76static char const * const count_objects_usage[] = {
  77        N_("git count-objects [-v]"),
  78        NULL
  79};
  80
  81int cmd_count_objects(int argc, const char **argv, const char *prefix)
  82{
  83        int i, verbose = 0;
  84        const char *objdir = get_object_directory();
  85        int len = strlen(objdir);
  86        char *path = xmalloc(len + 50);
  87        unsigned long loose = 0, packed = 0, packed_loose = 0;
  88        off_t loose_size = 0;
  89        struct option opts[] = {
  90                OPT__VERBOSE(&verbose, N_("be verbose")),
  91                OPT_END(),
  92        };
  93
  94        argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0);
  95        /* we do not take arguments other than flags for now */
  96        if (argc)
  97                usage_with_options(count_objects_usage, opts);
  98        if (verbose)
  99                report_garbage = real_report_garbage;
 100        memcpy(path, objdir, len);
 101        if (len && objdir[len-1] != '/')
 102                path[len++] = '/';
 103        for (i = 0; i < 256; i++) {
 104                DIR *d;
 105                sprintf(path + len, "%02x", i);
 106                d = opendir(path);
 107                if (!d)
 108                        continue;
 109                count_objects(d, path, len, verbose,
 110                              &loose, &loose_size, &packed_loose, &garbage);
 111                closedir(d);
 112        }
 113        if (verbose) {
 114                struct packed_git *p;
 115                unsigned long num_pack = 0;
 116                off_t size_pack = 0;
 117                if (!packed_git)
 118                        prepare_packed_git();
 119                for (p = packed_git; p; p = p->next) {
 120                        if (!p->pack_local)
 121                                continue;
 122                        if (open_pack_index(p))
 123                                continue;
 124                        packed += p->num_objects;
 125                        size_pack += p->pack_size + p->index_size;
 126                        num_pack++;
 127                }
 128                printf("count: %lu\n", loose);
 129                printf("size: %lu\n", (unsigned long) (loose_size / 1024));
 130                printf("in-pack: %lu\n", packed);
 131                printf("packs: %lu\n", num_pack);
 132                printf("size-pack: %lu\n", (unsigned long) (size_pack / 1024));
 133                printf("prune-packable: %lu\n", packed_loose);
 134                printf("garbage: %lu\n", garbage);
 135        }
 136        else
 137                printf("%lu objects, %lu kilobytes\n",
 138                       loose, (unsigned long) (loose_size / 1024));
 139        return 0;
 140}