server-info.con commit ls-tree: major rewrite to do pathspec (3c5e846)
   1#include "cache.h"
   2#include "refs.h"
   3#include "object.h"
   4#include "commit.h"
   5#include "tag.h"
   6
   7/* refs */
   8static FILE *info_ref_fp;
   9
  10static int add_info_ref(const char *path, const unsigned char *sha1)
  11{
  12        struct object *o = parse_object(sha1);
  13
  14        fprintf(info_ref_fp, "%s        %s\n", sha1_to_hex(sha1), path);
  15        if (o->type == tag_type) {
  16                o = deref_tag(o, path, 0);
  17                if (o)
  18                        fprintf(info_ref_fp, "%s        %s^{}\n",
  19                                sha1_to_hex(o->sha1), path);
  20        }
  21        return 0;
  22}
  23
  24static int update_info_refs(int force)
  25{
  26        char *path0 = strdup(git_path("info/refs"));
  27        int len = strlen(path0);
  28        char *path1 = xmalloc(len + 2);
  29
  30        strcpy(path1, path0);
  31        strcpy(path1 + len, "+");
  32
  33        safe_create_leading_directories(path0);
  34        info_ref_fp = fopen(path1, "w");
  35        if (!info_ref_fp)
  36                return error("unable to update %s", path0);
  37        for_each_ref(add_info_ref);
  38        fclose(info_ref_fp);
  39        rename(path1, path0);
  40        free(path0);
  41        free(path1);
  42        return 0;
  43}
  44
  45/* packs */
  46static struct pack_info {
  47        unsigned long latest;
  48        struct packed_git *p;
  49        int old_num;
  50        int new_num;
  51        int nr_alloc;
  52        int nr_heads;
  53        unsigned char (*head)[20];
  54        char dep[0]; /* more */
  55} **info;
  56static int num_pack;
  57static const char *objdir;
  58static int objdirlen;
  59
  60static struct object *parse_object_cheap(const unsigned char *sha1)
  61{
  62        struct object *o;
  63
  64        if ((o = parse_object(sha1)) == NULL)
  65                return NULL;
  66        if (o->type == commit_type) {
  67                struct commit *commit = (struct commit *)o;
  68                free(commit->buffer);
  69                commit->buffer = NULL;
  70        } else if (o->type == tree_type) {
  71                struct tree *tree = (struct tree *)o;
  72                struct tree_entry_list *e, *n;
  73                for (e = tree->entries; e; e = n) {
  74                        free(e->name);
  75                        e->name = NULL;
  76                        n = e->next;
  77                        free(e);
  78                }
  79                tree->entries = NULL;
  80        }
  81        return o;
  82}
  83
  84static struct pack_info *find_pack_by_name(const char *name)
  85{
  86        int i;
  87        for (i = 0; i < num_pack; i++) {
  88                struct packed_git *p = info[i]->p;
  89                /* skip "/pack/" after ".git/objects" */
  90                if (!strcmp(p->pack_name + objdirlen + 6, name))
  91                        return info[i];
  92        }
  93        return NULL;
  94}
  95
  96static struct pack_info *find_pack_by_old_num(int old_num)
  97{
  98        int i;
  99        for (i = 0; i < num_pack; i++)
 100                if (info[i]->old_num == old_num)
 101                        return info[i];
 102        return NULL;
 103}
 104
 105static int add_head_def(struct pack_info *this, unsigned char *sha1)
 106{
 107        if (this->nr_alloc <= this->nr_heads) {
 108                this->nr_alloc = alloc_nr(this->nr_alloc);
 109                this->head = xrealloc(this->head, this->nr_alloc * 20);
 110        }
 111        memcpy(this->head[this->nr_heads++], sha1, 20);
 112        return 0;
 113}
 114
 115/* Returns non-zero when we detect that the info in the
 116 * old file is useless.
 117 */
 118static int parse_pack_def(const char *line, int old_cnt)
 119{
 120        struct pack_info *i = find_pack_by_name(line + 2);
 121        if (i) {
 122                i->old_num = old_cnt;
 123                return 0;
 124        }
 125        else {
 126                /* The file describes a pack that is no longer here;
 127                 * dependencies between packs needs to be recalculated.
 128                 */
 129                return 1;
 130        }
 131}
 132
 133/* Returns non-zero when we detect that the info in the
 134 * old file is useless.
 135 */
 136static int parse_depend_def(char *line)
 137{
 138        unsigned long num;
 139        char *cp, *ep;
 140        struct pack_info *this, *that;
 141
 142        cp = line + 2;
 143        num = strtoul(cp, &ep, 10);
 144        if (ep == cp)
 145                return error("invalid input %s", line);
 146        this = find_pack_by_old_num(num);
 147        if (!this)
 148                return 0;
 149        while (ep && *(cp = ep)) {
 150                num = strtoul(cp, &ep, 10);
 151                if (ep == cp)
 152                        break;
 153                that = find_pack_by_old_num(num);
 154                if (!that)
 155                        /* The pack this one depends on does not
 156                         * exist; this should not happen because
 157                         * we write out the list of packs first and
 158                         * then dependency information, but it means
 159                         * the file is useless anyway.
 160                         */
 161                        return 1;
 162                this->dep[that->new_num] = 1;
 163        }
 164        return 0;
 165}
 166
 167/* Returns non-zero when we detect that the info in the
 168 * old file is useless.
 169 */
 170static int parse_head_def(char *line)
 171{
 172        unsigned char sha1[20];
 173        unsigned long num;
 174        char *cp, *ep;
 175        struct pack_info *this;
 176        struct object *o;
 177
 178        cp = line + 2;
 179        num = strtoul(cp, &ep, 10);
 180        if (ep == cp || *ep++ != ' ')
 181                return error("invalid input ix %s", line);
 182        this = find_pack_by_old_num(num);
 183        if (!this)
 184                return 1; /* You know the drill. */
 185        if (get_sha1_hex(ep, sha1) || ep[40] != ' ')
 186                return error("invalid input sha1 %s (%s)", line, ep);
 187        if ((o = parse_object_cheap(sha1)) == NULL)
 188                return error("no such object: %s", line);
 189        return add_head_def(this, sha1);
 190}
 191
 192/* Returns non-zero when we detect that the info in the
 193 * old file is useless.
 194 */
 195static int read_pack_info_file(const char *infofile)
 196{
 197        FILE *fp;
 198        char line[1000];
 199        int old_cnt = 0;
 200
 201        fp = fopen(infofile, "r");
 202        if (!fp)
 203                return 1; /* nonexisting is not an error. */
 204
 205        while (fgets(line, sizeof(line), fp)) {
 206                int len = strlen(line);
 207                if (line[len-1] == '\n')
 208                        line[len-1] = 0;
 209
 210                switch (line[0]) {
 211                case 'P': /* P name */
 212                        if (parse_pack_def(line, old_cnt++))
 213                                goto out_stale;
 214                        break;
 215                case 'D': /* D ix dep-ix1 dep-ix2... */
 216                        if (parse_depend_def(line))
 217                                goto out_stale;
 218                        break;
 219                case 'T': /* T ix sha1 type */
 220                        if (parse_head_def(line))
 221                                goto out_stale;
 222                        break;
 223                default:
 224                        error("unrecognized: %s", line);
 225                        break;
 226                }
 227        }
 228        fclose(fp);
 229        return 0;
 230 out_stale:
 231        fclose(fp);
 232        return 1;
 233}
 234
 235/* We sort the packs according to the date of the latest commit.  That
 236 * in turn indicates how young the pack is, and in general we would
 237 * want to depend on younger packs.
 238 */
 239static unsigned long get_latest_commit_date(struct packed_git *p)
 240{
 241        unsigned char sha1[20];
 242        struct object *o;
 243        int num = num_packed_objects(p);
 244        int i;
 245        unsigned long latest = 0;
 246
 247        for (i = 0; i < num; i++) {
 248                if (nth_packed_object_sha1(p, i, sha1))
 249                        die("corrupt pack file %s?", p->pack_name);
 250                if ((o = parse_object_cheap(sha1)) == NULL)
 251                        die("cannot parse %s", sha1_to_hex(sha1));
 252                if (o->type == commit_type) {
 253                        struct commit *commit = (struct commit *)o;
 254                        if (latest < commit->date)
 255                                latest = commit->date;
 256                }
 257        }
 258        return latest;
 259}
 260
 261static int compare_info(const void *a_, const void *b_)
 262{
 263        struct pack_info * const* a = a_;
 264        struct pack_info * const* b = b_;
 265
 266        if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
 267                /* Keep the order in the original */
 268                return (*a)->old_num - (*b)->old_num;
 269        else if (0 <= (*a)->old_num)
 270                /* Only A existed in the original so B is obviously newer */
 271                return -1;
 272        else if (0 <= (*b)->old_num)
 273                /* The other way around. */
 274                return 1;
 275
 276        if ((*a)->latest < (*b)->latest)
 277                return -1;
 278        else if ((*a)->latest == (*b)->latest)
 279                return 0;
 280        else
 281                return 1;
 282}
 283
 284static void init_pack_info(const char *infofile, int force)
 285{
 286        struct packed_git *p;
 287        int stale;
 288        int i = 0;
 289        char *dep_temp;
 290
 291        objdir = get_object_directory();
 292        objdirlen = strlen(objdir);
 293
 294        prepare_packed_git();
 295        for (p = packed_git; p; p = p->next) {
 296                /* we ignore things on alternate path since they are
 297                 * not available to the pullers in general.
 298                 */
 299                if (strncmp(p->pack_name, objdir, objdirlen) ||
 300                    strncmp(p->pack_name + objdirlen, "/pack/", 6))
 301                        continue;
 302                i++;
 303        }
 304        num_pack = i;
 305        info = xcalloc(num_pack, sizeof(struct pack_info *));
 306        for (i = 0, p = packed_git; p; p = p->next) {
 307                if (strncmp(p->pack_name, objdir, objdirlen) ||
 308                    p->pack_name[objdirlen] != '/')
 309                        continue;
 310                info[i] = xcalloc(1, sizeof(struct pack_info) + num_pack);
 311                info[i]->p = p;
 312                info[i]->old_num = -1;
 313                i++;
 314        }
 315
 316        if (infofile && !force)
 317                stale = read_pack_info_file(infofile);
 318        else
 319                stale = 1;
 320
 321        for (i = 0; i < num_pack; i++) {
 322                if (stale) {
 323                        info[i]->old_num = -1;
 324                        memset(info[i]->dep, 0, num_pack);
 325                        info[i]->nr_heads = 0;
 326                }
 327                if (info[i]->old_num < 0)
 328                        info[i]->latest = get_latest_commit_date(info[i]->p);
 329        }
 330
 331        qsort(info, num_pack, sizeof(info[0]), compare_info);
 332        for (i = 0; i < num_pack; i++)
 333                info[i]->new_num = i;
 334
 335        /* we need to fix up the dependency information
 336         * for the old ones.
 337         */
 338        dep_temp = NULL;
 339        for (i = 0; i < num_pack; i++) {
 340                int old;
 341
 342                if (info[i]->old_num < 0)
 343                        continue;
 344                if (! dep_temp)
 345                        dep_temp = xmalloc(num_pack);
 346                memset(dep_temp, 0, num_pack);
 347                for (old = 0; old < num_pack; old++) {
 348                        struct pack_info *base;
 349                        if (!info[i]->dep[old])
 350                                continue;
 351                        base = find_pack_by_old_num(old);
 352                        if (!base)
 353                                die("internal error renumbering");
 354                        dep_temp[base->new_num] = 1;
 355                }
 356                memcpy(info[i]->dep, dep_temp, num_pack);
 357        }
 358        free(dep_temp);
 359}
 360
 361static void write_pack_info_file(FILE *fp)
 362{
 363        int i, j;
 364        for (i = 0; i < num_pack; i++)
 365                fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6);
 366
 367        for (i = 0; i < num_pack; i++) {
 368                fprintf(fp, "D %1d", i);
 369                for (j = 0; j < num_pack; j++) {
 370                        if ((i == j) || !(info[i]->dep[j]))
 371                                continue;
 372                        fprintf(fp, " %1d", j);
 373                }
 374                fputc('\n', fp);
 375        }
 376
 377        for (i = 0; i < num_pack; i++) {
 378                struct pack_info *this = info[i];
 379                for (j = 0; j < this->nr_heads; j++) {
 380                        struct object *o = lookup_object(this->head[j]);
 381                        fprintf(fp, "T %1d %s %s\n",
 382                                i, sha1_to_hex(this->head[j]), o->type);
 383                }
 384        }
 385
 386}
 387
 388#define REFERENCED 01
 389#define INTERNAL  02
 390#define EMITTED   04
 391
 392static void show(struct object *o, int pack_ix)
 393{
 394        /*
 395         * We are interested in objects that are not referenced,
 396         * and objects that are referenced but not internal.
 397         */
 398        if (o->flags & EMITTED)
 399                return;
 400
 401        if (!(o->flags & REFERENCED))
 402                add_head_def(info[pack_ix], o->sha1);
 403        else if ((o->flags & REFERENCED) && !(o->flags & INTERNAL)) {
 404                int i;
 405
 406                /* Which pack contains this object?  That is what
 407                 * pack_ix can depend on.  We earlier sorted info
 408                 * array from youngest to oldest, so try newer packs
 409                 * first to favor them here.
 410                 */
 411                for (i = num_pack - 1; 0 <= i; i--) {
 412                        struct packed_git *p = info[i]->p;
 413                        struct pack_entry ent;
 414                        if (find_pack_entry_one(o->sha1, &ent, p)) {
 415                                info[pack_ix]->dep[i] = 1;
 416                                break;
 417                        }
 418                }
 419        }
 420        o->flags |= EMITTED;
 421}
 422
 423static void find_pack_info_one(int pack_ix)
 424{
 425        unsigned char sha1[20];
 426        struct object *o;
 427        int i;
 428        struct packed_git *p = info[pack_ix]->p;
 429        int num = num_packed_objects(p);
 430
 431        /* Scan objects, clear flags from all the edge ones and
 432         * internal ones, possibly marked in the previous round.
 433         */
 434        for (i = 0; i < num; i++) {
 435                if (nth_packed_object_sha1(p, i, sha1))
 436                        die("corrupt pack file %s?", p->pack_name);
 437                if ((o = lookup_object(sha1)) == NULL)
 438                        die("cannot parse %s", sha1_to_hex(sha1));
 439                if (o->refs) {
 440                        struct object_refs *refs = o->refs;
 441                        int j;
 442                        for (j = 0; j < refs->count; j++)
 443                                refs->ref[j]->flags = 0;
 444                }
 445                o->flags = 0;
 446        }
 447
 448        /* Mark all the internal ones */
 449        for (i = 0; i < num; i++) {
 450                if (nth_packed_object_sha1(p, i, sha1))
 451                        die("corrupt pack file %s?", p->pack_name);
 452                if ((o = lookup_object(sha1)) == NULL)
 453                        die("cannot find %s", sha1_to_hex(sha1));
 454                if (o->refs) {
 455                        struct object_refs *refs = o->refs;
 456                        int j;
 457                        for (j = 0; j < refs->count; j++)
 458                                refs->ref[j]->flags |= REFERENCED;
 459                }
 460                o->flags |= INTERNAL;
 461        }
 462
 463        for (i = 0; i < num; i++) {
 464                if (nth_packed_object_sha1(p, i, sha1))
 465                        die("corrupt pack file %s?", p->pack_name);
 466                if ((o = lookup_object(sha1)) == NULL)
 467                        die("cannot find %s", sha1_to_hex(sha1));
 468
 469                show(o, pack_ix);
 470                if (o->refs) {
 471                        struct object_refs *refs = o->refs;
 472                        int j;
 473                        for (j = 0; j < refs->count; j++)
 474                                show(refs->ref[j], pack_ix);
 475                }
 476        }
 477
 478}
 479
 480static void find_pack_info(void)
 481{
 482        int i;
 483        for (i = 0; i < num_pack; i++) {
 484                /* The packed objects are cast in stone, and a head
 485                 * in a pack will stay as head, so is the set of missing
 486                 * objects.  If the repo has been reorganized and we
 487                 * are missing some packs available back then, we have
 488                 * already discarded the info read from the file, so
 489                 * we will find (old_num < 0) in that case.
 490                 */
 491                if (0 <= info[i]->old_num)
 492                        continue;
 493                find_pack_info_one(i);
 494        }
 495}
 496
 497static int update_info_packs(int force)
 498{
 499        char infofile[PATH_MAX];
 500        char name[PATH_MAX];
 501        int namelen;
 502        FILE *fp;
 503
 504        namelen = sprintf(infofile, "%s/info/packs", get_object_directory());
 505        strcpy(name, infofile);
 506        strcpy(name + namelen, "+");
 507
 508        init_pack_info(infofile, force);
 509        find_pack_info();
 510
 511        safe_create_leading_directories(name);
 512        fp = fopen(name, "w");
 513        if (!fp)
 514                return error("cannot open %s", name);
 515        write_pack_info_file(fp);
 516        fclose(fp);
 517        rename(name, infofile);
 518        return 0;
 519}
 520
 521/* public */
 522int update_server_info(int force)
 523{
 524        /* We would add more dumb-server support files later,
 525         * including index of available pack files and their
 526         * intended audiences.
 527         */
 528        int errs = 0;
 529
 530        errs = errs | update_info_refs(force);
 531        errs = errs | update_info_packs(force);
 532
 533        return errs;
 534}