builtin-count.con commit simple euristic for further free packing improvements (4e8da19)
   1/*
   2 * Builtin "git count-objects".
   3 *
   4 * Copyright (c) 2006 Junio C Hamano
   5 */
   6
   7#include "cache.h"
   8#include "builtin.h"
   9
  10static const char count_objects_usage[] = "git-count-objects [-v]";
  11
  12static void count_objects(DIR *d, char *path, int len, int verbose,
  13                          unsigned long *loose,
  14                          unsigned long *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 ((ent->d_name[0] == '.') &&
  26                    (ent->d_name[1] == 0 ||
  27                     ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))))
  28                        continue;
  29                for (cp = ent->d_name; *cp; cp++) {
  30                        int ch = *cp;
  31                        if (('0' <= ch && ch <= '9') ||
  32                            ('a' <= ch && ch <= 'f'))
  33                                continue;
  34                        bad = 1;
  35                        break;
  36                }
  37                if (cp - ent->d_name != 38)
  38                        bad = 1;
  39                else {
  40                        struct stat st;
  41                        memcpy(path + len + 3, ent->d_name, 38);
  42                        path[len + 2] = '/';
  43                        path[len + 41] = 0;
  44                        if (lstat(path, &st) || !S_ISREG(st.st_mode))
  45                                bad = 1;
  46                        else
  47                                (*loose_size) += st.st_blocks;
  48                }
  49                if (bad) {
  50                        if (verbose) {
  51                                error("garbage found: %.*s/%s",
  52                                      len + 2, path, ent->d_name);
  53                                (*garbage)++;
  54                        }
  55                        continue;
  56                }
  57                (*loose)++;
  58                if (!verbose)
  59                        continue;
  60                memcpy(hex, path+len, 2);
  61                memcpy(hex+2, ent->d_name, 38);
  62                hex[40] = 0;
  63                if (get_sha1_hex(hex, sha1))
  64                        die("internal error");
  65                if (has_sha1_pack(sha1))
  66                        (*packed_loose)++;
  67        }
  68}
  69
  70int cmd_count_objects(int ac, const char **av, char **ep)
  71{
  72        int i;
  73        int verbose = 0;
  74        const char *objdir = get_object_directory();
  75        int len = strlen(objdir);
  76        char *path = xmalloc(len + 50);
  77        unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
  78        unsigned long loose_size = 0;
  79
  80        for (i = 1; i < ac; i++) {
  81                const char *arg = av[i];
  82                if (*arg != '-')
  83                        break;
  84                else if (!strcmp(arg, "-v"))
  85                        verbose = 1;
  86                else
  87                        usage(count_objects_usage);
  88        }
  89
  90        /* we do not take arguments other than flags for now */
  91        if (i < ac)
  92                usage(count_objects_usage);
  93        memcpy(path, objdir, len);
  94        if (len && objdir[len-1] != '/')
  95                path[len++] = '/';
  96        for (i = 0; i < 256; i++) {
  97                DIR *d;
  98                sprintf(path + len, "%02x", i);
  99                d = opendir(path);
 100                if (!d)
 101                        continue;
 102                count_objects(d, path, len, verbose,
 103                              &loose, &loose_size, &packed_loose, &garbage);
 104                closedir(d);
 105        }
 106        if (verbose) {
 107                struct packed_git *p;
 108                if (!packed_git)
 109                        prepare_packed_git();
 110                for (p = packed_git; p; p = p->next) {
 111                        if (!p->pack_local)
 112                                continue;
 113                        packed += num_packed_objects(p);
 114                }
 115                printf("count: %lu\n", loose);
 116                printf("size: %lu\n", loose_size / 2);
 117                printf("in-pack: %lu\n", packed);
 118                printf("prune-packable: %lu\n", packed_loose);
 119                printf("garbage: %lu\n", garbage);
 120        }
 121        else
 122                printf("%lu objects, %lu kilobytes\n",
 123                       loose, loose_size / 2);
 124        return 0;
 125}