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