builtin-pack-refs.con commit Merge branch 'lt/refs' into jc/lt-ref2-with-lt-refs (eaf12a8)
   1#include "cache.h"
   2#include "refs.h"
   3
   4static const char *result_path, *lock_path;
   5static const char builtin_pack_refs_usage[] =
   6"git-pack-refs [--prune]";
   7
   8struct ref_to_prune {
   9        struct ref_to_prune *next;
  10        unsigned char sha1[20];
  11        char name[FLEX_ARRAY];
  12};
  13
  14struct pack_refs_cb_data {
  15        int prune;
  16        struct ref_to_prune *ref_to_prune;
  17        FILE *refs_file;
  18};
  19
  20static void remove_lock_file(void)
  21{
  22        if (lock_path)
  23                unlink(lock_path);
  24}
  25
  26static int do_not_prune(int flags)
  27{
  28        /* If it is already packed or if it is a symref,
  29         * do not prune it.
  30         */
  31        return (flags & (REF_ISSYMREF|REF_ISPACKED));
  32}
  33
  34static int handle_one_ref(const char *path, const unsigned char *sha1,
  35                          int flags, void *cb_data)
  36{
  37        struct pack_refs_cb_data *cb = cb_data;
  38
  39        /* Do not pack the symbolic refs */
  40        if (!(flags & REF_ISSYMREF))
  41                fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
  42        if (cb->prune && !do_not_prune(flags)) {
  43                int namelen = strlen(path) + 1;
  44                struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
  45                hashcpy(n->sha1, sha1);
  46                strcpy(n->name, path);
  47                n->next = cb->ref_to_prune;
  48                cb->ref_to_prune = n;
  49        }
  50        return 0;
  51}
  52
  53/* make sure nobody touched the ref, and unlink */
  54static void prune_ref(struct ref_to_prune *r)
  55{
  56        struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1, 1);
  57
  58        if (lock) {
  59                unlink(git_path(r->name));
  60                unlock_ref(lock);
  61        }
  62}
  63
  64static void prune_refs(struct ref_to_prune *r)
  65{
  66        while (r) {
  67                prune_ref(r);
  68                r = r->next;
  69        }
  70}
  71
  72int cmd_pack_refs(int argc, const char **argv, const char *prefix)
  73{
  74        int fd, i;
  75        struct pack_refs_cb_data cbdata;
  76
  77        memset(&cbdata, 0, sizeof(cbdata));
  78
  79        for (i = 1; i < argc; i++) {
  80                const char *arg = argv[i];
  81                if (!strcmp(arg, "--prune")) {
  82                        cbdata.prune = 1;
  83                        continue;
  84                }
  85                /* perhaps other parameters later... */
  86                break;
  87        }
  88        if (i != argc)
  89                usage(builtin_pack_refs_usage);
  90
  91        result_path = xstrdup(git_path("packed-refs"));
  92        lock_path = xstrdup(mkpath("%s.lock", result_path));
  93
  94        fd = open(lock_path, O_CREAT | O_EXCL | O_WRONLY, 0666);
  95        if (fd < 0)
  96                die("unable to create new ref-pack file (%s)", strerror(errno));
  97        atexit(remove_lock_file);
  98
  99        cbdata.refs_file = fdopen(fd, "w");
 100        if (!cbdata.refs_file)
 101                die("unable to create ref-pack file structure (%s)",
 102                    strerror(errno));
 103        for_each_ref(handle_one_ref, &cbdata);
 104        fsync(fd);
 105        fclose(cbdata.refs_file);
 106        if (rename(lock_path, result_path) < 0)
 107                die("unable to overwrite old ref-pack file (%s)", strerror(errno));
 108        lock_path = NULL;
 109        if (cbdata.prune)
 110                prune_refs(cbdata.ref_to_prune);
 111        return 0;
 112}