builtin / count-objects.con commit refs.c: allow listing and deleting badly named refs (d0f810f)
   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;
  13static off_t size_garbage;
  14
  15static void real_report_garbage(const char *desc, const char *path)
  16{
  17        struct stat st;
  18        if (!stat(path, &st))
  19                size_garbage += st.st_size;
  20        warning("%s: %s", desc, path);
  21        garbage++;
  22}
  23
  24static void count_objects(DIR *d, char *path, int len, int verbose,
  25                          unsigned long *loose,
  26                          off_t *loose_size,
  27                          unsigned long *packed_loose)
  28{
  29        struct dirent *ent;
  30        while ((ent = readdir(d)) != NULL) {
  31                char hex[41];
  32                unsigned char sha1[20];
  33                const char *cp;
  34                int bad = 0;
  35
  36                if (is_dot_or_dotdot(ent->d_name))
  37                        continue;
  38                for (cp = ent->d_name; *cp; cp++) {
  39                        int ch = *cp;
  40                        if (('0' <= ch && ch <= '9') ||
  41                            ('a' <= ch && ch <= 'f'))
  42                                continue;
  43                        bad = 1;
  44                        break;
  45                }
  46                if (cp - ent->d_name != 38)
  47                        bad = 1;
  48                else {
  49                        struct stat st;
  50                        memcpy(path + len + 3, ent->d_name, 38);
  51                        path[len + 2] = '/';
  52                        path[len + 41] = 0;
  53                        if (lstat(path, &st) || !S_ISREG(st.st_mode))
  54                                bad = 1;
  55                        else
  56                                (*loose_size) += xsize_t(on_disk_bytes(st));
  57                }
  58                if (bad) {
  59                        if (verbose) {
  60                                struct strbuf sb = STRBUF_INIT;
  61                                strbuf_addf(&sb, "%.*s/%s",
  62                                            len + 2, path, ent->d_name);
  63                                report_garbage("garbage found", sb.buf);
  64                                strbuf_release(&sb);
  65                        }
  66                        continue;
  67                }
  68                (*loose)++;
  69                if (!verbose)
  70                        continue;
  71                memcpy(hex, path+len, 2);
  72                memcpy(hex+2, ent->d_name, 38);
  73                hex[40] = 0;
  74                if (get_sha1_hex(hex, sha1))
  75                        die("internal error");
  76                if (has_sha1_pack(sha1))
  77                        (*packed_loose)++;
  78        }
  79}
  80
  81static char const * const count_objects_usage[] = {
  82        N_("git count-objects [-v] [-H | --human-readable]"),
  83        NULL
  84};
  85
  86int cmd_count_objects(int argc, const char **argv, const char *prefix)
  87{
  88        int i, verbose = 0, human_readable = 0;
  89        const char *objdir = get_object_directory();
  90        int len = strlen(objdir);
  91        char *path = xmalloc(len + 50);
  92        unsigned long loose = 0, packed = 0, packed_loose = 0;
  93        off_t loose_size = 0;
  94        struct option opts[] = {
  95                OPT__VERBOSE(&verbose, N_("be verbose")),
  96                OPT_BOOL('H', "human-readable", &human_readable,
  97                         N_("print sizes in human readable format")),
  98                OPT_END(),
  99        };
 100
 101        argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0);
 102        /* we do not take arguments other than flags for now */
 103        if (argc)
 104                usage_with_options(count_objects_usage, opts);
 105        if (verbose)
 106                report_garbage = real_report_garbage;
 107        memcpy(path, objdir, len);
 108        if (len && objdir[len-1] != '/')
 109                path[len++] = '/';
 110        for (i = 0; i < 256; i++) {
 111                DIR *d;
 112                sprintf(path + len, "%02x", i);
 113                d = opendir(path);
 114                if (!d)
 115                        continue;
 116                count_objects(d, path, len, verbose,
 117                              &loose, &loose_size, &packed_loose);
 118                closedir(d);
 119        }
 120        if (verbose) {
 121                struct packed_git *p;
 122                unsigned long num_pack = 0;
 123                off_t size_pack = 0;
 124                struct strbuf loose_buf = STRBUF_INIT;
 125                struct strbuf pack_buf = STRBUF_INIT;
 126                struct strbuf garbage_buf = STRBUF_INIT;
 127                if (!packed_git)
 128                        prepare_packed_git();
 129                for (p = packed_git; p; p = p->next) {
 130                        if (!p->pack_local)
 131                                continue;
 132                        if (open_pack_index(p))
 133                                continue;
 134                        packed += p->num_objects;
 135                        size_pack += p->pack_size + p->index_size;
 136                        num_pack++;
 137                }
 138
 139                if (human_readable) {
 140                        strbuf_humanise_bytes(&loose_buf, loose_size);
 141                        strbuf_humanise_bytes(&pack_buf, size_pack);
 142                        strbuf_humanise_bytes(&garbage_buf, size_garbage);
 143                } else {
 144                        strbuf_addf(&loose_buf, "%lu",
 145                                    (unsigned long)(loose_size / 1024));
 146                        strbuf_addf(&pack_buf, "%lu",
 147                                    (unsigned long)(size_pack / 1024));
 148                        strbuf_addf(&garbage_buf, "%lu",
 149                                    (unsigned long)(size_garbage / 1024));
 150                }
 151
 152                printf("count: %lu\n", loose);
 153                printf("size: %s\n", loose_buf.buf);
 154                printf("in-pack: %lu\n", packed);
 155                printf("packs: %lu\n", num_pack);
 156                printf("size-pack: %s\n", pack_buf.buf);
 157                printf("prune-packable: %lu\n", packed_loose);
 158                printf("garbage: %lu\n", garbage);
 159                printf("size-garbage: %s\n", garbage_buf.buf);
 160                strbuf_release(&loose_buf);
 161                strbuf_release(&pack_buf);
 162                strbuf_release(&garbage_buf);
 163        } else {
 164                struct strbuf buf = STRBUF_INIT;
 165                if (human_readable)
 166                        strbuf_humanise_bytes(&buf, loose_size);
 167                else
 168                        strbuf_addf(&buf, "%lu kilobytes",
 169                                    (unsigned long)(loose_size / 1024));
 170                printf("%lu objects, %s\n", loose, buf.buf);
 171                strbuf_release(&buf);
 172        }
 173        return 0;
 174}