builtin-receive-pack.con commit tests: update tests that used to fail (df3dac3)
   1#include "cache.h"
   2#include "pack.h"
   3#include "refs.h"
   4#include "pkt-line.h"
   5#include "run-command.h"
   6#include "exec_cmd.h"
   7#include "commit.h"
   8#include "object.h"
   9#include "remote.h"
  10#include "transport.h"
  11
  12static const char receive_pack_usage[] = "git receive-pack <git-dir>";
  13
  14enum deny_action {
  15        DENY_UNCONFIGURED,
  16        DENY_IGNORE,
  17        DENY_WARN,
  18        DENY_REFUSE,
  19};
  20
  21static int deny_deletes;
  22static int deny_non_fast_forwards;
  23static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
  24static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
  25static int receive_fsck_objects;
  26static int receive_unpack_limit = -1;
  27static int transfer_unpack_limit = -1;
  28static int unpack_limit = 100;
  29static int report_status;
  30static int prefer_ofs_delta = 1;
  31static int auto_update_server_info;
  32static int auto_gc = 1;
  33static const char *head_name;
  34static char *capabilities_to_send;
  35
  36static enum deny_action parse_deny_action(const char *var, const char *value)
  37{
  38        if (value) {
  39                if (!strcasecmp(value, "ignore"))
  40                        return DENY_IGNORE;
  41                if (!strcasecmp(value, "warn"))
  42                        return DENY_WARN;
  43                if (!strcasecmp(value, "refuse"))
  44                        return DENY_REFUSE;
  45        }
  46        if (git_config_bool(var, value))
  47                return DENY_REFUSE;
  48        return DENY_IGNORE;
  49}
  50
  51static int receive_pack_config(const char *var, const char *value, void *cb)
  52{
  53        if (strcmp(var, "receive.denydeletes") == 0) {
  54                deny_deletes = git_config_bool(var, value);
  55                return 0;
  56        }
  57
  58        if (strcmp(var, "receive.denynonfastforwards") == 0) {
  59                deny_non_fast_forwards = git_config_bool(var, value);
  60                return 0;
  61        }
  62
  63        if (strcmp(var, "receive.unpacklimit") == 0) {
  64                receive_unpack_limit = git_config_int(var, value);
  65                return 0;
  66        }
  67
  68        if (strcmp(var, "transfer.unpacklimit") == 0) {
  69                transfer_unpack_limit = git_config_int(var, value);
  70                return 0;
  71        }
  72
  73        if (strcmp(var, "receive.fsckobjects") == 0) {
  74                receive_fsck_objects = git_config_bool(var, value);
  75                return 0;
  76        }
  77
  78        if (!strcmp(var, "receive.denycurrentbranch")) {
  79                deny_current_branch = parse_deny_action(var, value);
  80                return 0;
  81        }
  82
  83        if (strcmp(var, "receive.denydeletecurrent") == 0) {
  84                deny_delete_current = parse_deny_action(var, value);
  85                return 0;
  86        }
  87
  88        if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
  89                prefer_ofs_delta = git_config_bool(var, value);
  90                return 0;
  91        }
  92
  93        if (strcmp(var, "receive.updateserverinfo") == 0) {
  94                auto_update_server_info = git_config_bool(var, value);
  95                return 0;
  96        }
  97
  98        if (strcmp(var, "receive.autogc") == 0) {
  99                auto_gc = git_config_bool(var, value);
 100                return 0;
 101        }
 102
 103        return git_default_config(var, value, cb);
 104}
 105
 106static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 107{
 108        if (!capabilities_to_send)
 109                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
 110        else
 111                packet_write(1, "%s %s%c%s\n",
 112                             sha1_to_hex(sha1), path, 0, capabilities_to_send);
 113        capabilities_to_send = NULL;
 114        return 0;
 115}
 116
 117static void write_head_info(void)
 118{
 119        for_each_ref(show_ref, NULL);
 120        if (capabilities_to_send)
 121                show_ref("capabilities^{}", null_sha1, 0, NULL);
 122
 123}
 124
 125struct command {
 126        struct command *next;
 127        const char *error_string;
 128        unsigned char old_sha1[20];
 129        unsigned char new_sha1[20];
 130        char ref_name[FLEX_ARRAY]; /* more */
 131};
 132
 133static struct command *commands;
 134
 135static const char pre_receive_hook[] = "hooks/pre-receive";
 136static const char post_receive_hook[] = "hooks/post-receive";
 137
 138static int run_receive_hook(const char *hook_name)
 139{
 140        static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
 141        struct command *cmd;
 142        struct child_process proc;
 143        const char *argv[2];
 144        int have_input = 0, code;
 145
 146        for (cmd = commands; !have_input && cmd; cmd = cmd->next) {
 147                if (!cmd->error_string)
 148                        have_input = 1;
 149        }
 150
 151        if (!have_input || access(hook_name, X_OK) < 0)
 152                return 0;
 153
 154        argv[0] = hook_name;
 155        argv[1] = NULL;
 156
 157        memset(&proc, 0, sizeof(proc));
 158        proc.argv = argv;
 159        proc.in = -1;
 160        proc.stdout_to_stderr = 1;
 161
 162        code = start_command(&proc);
 163        if (code)
 164                return code;
 165        for (cmd = commands; cmd; cmd = cmd->next) {
 166                if (!cmd->error_string) {
 167                        size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
 168                                sha1_to_hex(cmd->old_sha1),
 169                                sha1_to_hex(cmd->new_sha1),
 170                                cmd->ref_name);
 171                        if (write_in_full(proc.in, buf, n) != n)
 172                                break;
 173                }
 174        }
 175        close(proc.in);
 176        return finish_command(&proc);
 177}
 178
 179static int run_update_hook(struct command *cmd)
 180{
 181        static const char update_hook[] = "hooks/update";
 182        const char *argv[5];
 183
 184        if (access(update_hook, X_OK) < 0)
 185                return 0;
 186
 187        argv[0] = update_hook;
 188        argv[1] = cmd->ref_name;
 189        argv[2] = sha1_to_hex(cmd->old_sha1);
 190        argv[3] = sha1_to_hex(cmd->new_sha1);
 191        argv[4] = NULL;
 192
 193        return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
 194                                        RUN_COMMAND_STDOUT_TO_STDERR);
 195}
 196
 197static int is_ref_checked_out(const char *ref)
 198{
 199        if (is_bare_repository())
 200                return 0;
 201
 202        if (!head_name)
 203                return 0;
 204        return !strcmp(head_name, ref);
 205}
 206
 207static char *refuse_unconfigured_deny_msg[] = {
 208        "By default, updating the current branch in a non-bare repository",
 209        "is denied, because it will make the index and work tree inconsistent",
 210        "with what you pushed, and will require 'git reset --hard' to match",
 211        "the work tree to HEAD.",
 212        "",
 213        "You can set 'receive.denyCurrentBranch' configuration variable to",
 214        "'ignore' or 'warn' in the remote repository to allow pushing into",
 215        "its current branch; however, this is not recommended unless you",
 216        "arranged to update its work tree to match what you pushed in some",
 217        "other way.",
 218        "",
 219        "To squelch this message and still keep the default behaviour, set",
 220        "'receive.denyCurrentBranch' configuration variable to 'refuse'."
 221};
 222
 223static void refuse_unconfigured_deny(void)
 224{
 225        int i;
 226        for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
 227                error("%s", refuse_unconfigured_deny_msg[i]);
 228}
 229
 230static char *refuse_unconfigured_deny_delete_current_msg[] = {
 231        "By default, deleting the current branch is denied, because the next",
 232        "'git clone' won't result in any file checked out, causing confusion.",
 233        "",
 234        "You can set 'receive.denyDeleteCurrent' configuration variable to",
 235        "'warn' or 'ignore' in the remote repository to allow deleting the",
 236        "current branch, with or without a warning message.",
 237        "",
 238        "To squelch this message, you can set it to 'refuse'."
 239};
 240
 241static void refuse_unconfigured_deny_delete_current(void)
 242{
 243        int i;
 244        for (i = 0;
 245             i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
 246             i++)
 247                error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 248}
 249
 250static const char *update(struct command *cmd)
 251{
 252        const char *name = cmd->ref_name;
 253        unsigned char *old_sha1 = cmd->old_sha1;
 254        unsigned char *new_sha1 = cmd->new_sha1;
 255        struct ref_lock *lock;
 256
 257        /* only refs/... are allowed */
 258        if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
 259                error("refusing to create funny ref '%s' remotely", name);
 260                return "funny refname";
 261        }
 262
 263        if (is_ref_checked_out(name)) {
 264                switch (deny_current_branch) {
 265                case DENY_IGNORE:
 266                        break;
 267                case DENY_WARN:
 268                        warning("updating the current branch");
 269                        break;
 270                case DENY_REFUSE:
 271                case DENY_UNCONFIGURED:
 272                        error("refusing to update checked out branch: %s", name);
 273                        if (deny_current_branch == DENY_UNCONFIGURED)
 274                                refuse_unconfigured_deny();
 275                        return "branch is currently checked out";
 276                }
 277        }
 278
 279        if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) {
 280                error("unpack should have generated %s, "
 281                      "but I can't find it!", sha1_to_hex(new_sha1));
 282                return "bad pack";
 283        }
 284
 285        if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
 286                if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
 287                        error("denying ref deletion for %s", name);
 288                        return "deletion prohibited";
 289                }
 290
 291                if (!strcmp(name, head_name)) {
 292                        switch (deny_delete_current) {
 293                        case DENY_IGNORE:
 294                                break;
 295                        case DENY_WARN:
 296                                warning("deleting the current branch");
 297                                break;
 298                        case DENY_REFUSE:
 299                        case DENY_UNCONFIGURED:
 300                                if (deny_delete_current == DENY_UNCONFIGURED)
 301                                        refuse_unconfigured_deny_delete_current();
 302                                error("refusing to delete the current branch: %s", name);
 303                                return "deletion of the current branch prohibited";
 304                        }
 305                }
 306        }
 307
 308        if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
 309            !is_null_sha1(old_sha1) &&
 310            !prefixcmp(name, "refs/heads/")) {
 311                struct object *old_object, *new_object;
 312                struct commit *old_commit, *new_commit;
 313                struct commit_list *bases, *ent;
 314
 315                old_object = parse_object(old_sha1);
 316                new_object = parse_object(new_sha1);
 317
 318                if (!old_object || !new_object ||
 319                    old_object->type != OBJ_COMMIT ||
 320                    new_object->type != OBJ_COMMIT) {
 321                        error("bad sha1 objects for %s", name);
 322                        return "bad ref";
 323                }
 324                old_commit = (struct commit *)old_object;
 325                new_commit = (struct commit *)new_object;
 326                bases = get_merge_bases(old_commit, new_commit, 1);
 327                for (ent = bases; ent; ent = ent->next)
 328                        if (!hashcmp(old_sha1, ent->item->object.sha1))
 329                                break;
 330                free_commit_list(bases);
 331                if (!ent) {
 332                        error("denying non-fast-forward %s"
 333                              " (you should pull first)", name);
 334                        return "non-fast-forward";
 335                }
 336        }
 337        if (run_update_hook(cmd)) {
 338                error("hook declined to update %s", name);
 339                return "hook declined";
 340        }
 341
 342        if (is_null_sha1(new_sha1)) {
 343                if (!parse_object(old_sha1)) {
 344                        warning ("Allowing deletion of corrupt ref.");
 345                        old_sha1 = NULL;
 346                }
 347                if (delete_ref(name, old_sha1, 0)) {
 348                        error("failed to delete %s", name);
 349                        return "failed to delete";
 350                }
 351                return NULL; /* good */
 352        }
 353        else {
 354                lock = lock_any_ref_for_update(name, old_sha1, 0);
 355                if (!lock) {
 356                        error("failed to lock %s", name);
 357                        return "failed to lock";
 358                }
 359                if (write_ref_sha1(lock, new_sha1, "push")) {
 360                        return "failed to write"; /* error() already called */
 361                }
 362                return NULL; /* good */
 363        }
 364}
 365
 366static char update_post_hook[] = "hooks/post-update";
 367
 368static void run_update_post_hook(struct command *cmd)
 369{
 370        struct command *cmd_p;
 371        int argc, status;
 372        const char **argv;
 373
 374        for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 375                if (cmd_p->error_string)
 376                        continue;
 377                argc++;
 378        }
 379        if (!argc || access(update_post_hook, X_OK) < 0)
 380                return;
 381        argv = xmalloc(sizeof(*argv) * (2 + argc));
 382        argv[0] = update_post_hook;
 383
 384        for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 385                char *p;
 386                if (cmd_p->error_string)
 387                        continue;
 388                p = xmalloc(strlen(cmd_p->ref_name) + 1);
 389                strcpy(p, cmd_p->ref_name);
 390                argv[argc] = p;
 391                argc++;
 392        }
 393        argv[argc] = NULL;
 394        status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
 395                        | RUN_COMMAND_STDOUT_TO_STDERR);
 396}
 397
 398static void execute_commands(const char *unpacker_error)
 399{
 400        struct command *cmd = commands;
 401        unsigned char sha1[20];
 402
 403        if (unpacker_error) {
 404                while (cmd) {
 405                        cmd->error_string = "n/a (unpacker error)";
 406                        cmd = cmd->next;
 407                }
 408                return;
 409        }
 410
 411        if (run_receive_hook(pre_receive_hook)) {
 412                while (cmd) {
 413                        cmd->error_string = "pre-receive hook declined";
 414                        cmd = cmd->next;
 415                }
 416                return;
 417        }
 418
 419        head_name = resolve_ref("HEAD", sha1, 0, NULL);
 420
 421        while (cmd) {
 422                cmd->error_string = update(cmd);
 423                cmd = cmd->next;
 424        }
 425}
 426
 427static void read_head_info(void)
 428{
 429        struct command **p = &commands;
 430        for (;;) {
 431                static char line[1000];
 432                unsigned char old_sha1[20], new_sha1[20];
 433                struct command *cmd;
 434                char *refname;
 435                int len, reflen;
 436
 437                len = packet_read_line(0, line, sizeof(line));
 438                if (!len)
 439                        break;
 440                if (line[len-1] == '\n')
 441                        line[--len] = 0;
 442                if (len < 83 ||
 443                    line[40] != ' ' ||
 444                    line[81] != ' ' ||
 445                    get_sha1_hex(line, old_sha1) ||
 446                    get_sha1_hex(line + 41, new_sha1))
 447                        die("protocol error: expected old/new/ref, got '%s'",
 448                            line);
 449
 450                refname = line + 82;
 451                reflen = strlen(refname);
 452                if (reflen + 82 < len) {
 453                        if (strstr(refname + reflen + 1, "report-status"))
 454                                report_status = 1;
 455                }
 456                cmd = xmalloc(sizeof(struct command) + len - 80);
 457                hashcpy(cmd->old_sha1, old_sha1);
 458                hashcpy(cmd->new_sha1, new_sha1);
 459                memcpy(cmd->ref_name, line + 82, len - 81);
 460                cmd->error_string = NULL;
 461                cmd->next = NULL;
 462                *p = cmd;
 463                p = &cmd->next;
 464        }
 465}
 466
 467static const char *parse_pack_header(struct pack_header *hdr)
 468{
 469        switch (read_pack_header(0, hdr)) {
 470        case PH_ERROR_EOF:
 471                return "eof before pack header was fully read";
 472
 473        case PH_ERROR_PACK_SIGNATURE:
 474                return "protocol error (pack signature mismatch detected)";
 475
 476        case PH_ERROR_PROTOCOL:
 477                return "protocol error (pack version unsupported)";
 478
 479        default:
 480                return "unknown error in parse_pack_header";
 481
 482        case 0:
 483                return NULL;
 484        }
 485}
 486
 487static const char *pack_lockfile;
 488
 489static const char *unpack(void)
 490{
 491        struct pack_header hdr;
 492        const char *hdr_err;
 493        char hdr_arg[38];
 494
 495        hdr_err = parse_pack_header(&hdr);
 496        if (hdr_err)
 497                return hdr_err;
 498        snprintf(hdr_arg, sizeof(hdr_arg),
 499                        "--pack_header=%"PRIu32",%"PRIu32,
 500                        ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
 501
 502        if (ntohl(hdr.hdr_entries) < unpack_limit) {
 503                int code, i = 0;
 504                const char *unpacker[4];
 505                unpacker[i++] = "unpack-objects";
 506                if (receive_fsck_objects)
 507                        unpacker[i++] = "--strict";
 508                unpacker[i++] = hdr_arg;
 509                unpacker[i++] = NULL;
 510                code = run_command_v_opt(unpacker, RUN_GIT_CMD);
 511                if (!code)
 512                        return NULL;
 513                return "unpack-objects abnormal exit";
 514        } else {
 515                const char *keeper[7];
 516                int s, status, i = 0;
 517                char keep_arg[256];
 518                struct child_process ip;
 519
 520                s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid());
 521                if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
 522                        strcpy(keep_arg + s, "localhost");
 523
 524                keeper[i++] = "index-pack";
 525                keeper[i++] = "--stdin";
 526                if (receive_fsck_objects)
 527                        keeper[i++] = "--strict";
 528                keeper[i++] = "--fix-thin";
 529                keeper[i++] = hdr_arg;
 530                keeper[i++] = keep_arg;
 531                keeper[i++] = NULL;
 532                memset(&ip, 0, sizeof(ip));
 533                ip.argv = keeper;
 534                ip.out = -1;
 535                ip.git_cmd = 1;
 536                status = start_command(&ip);
 537                if (status) {
 538                        return "index-pack fork failed";
 539                }
 540                pack_lockfile = index_pack_lockfile(ip.out);
 541                close(ip.out);
 542                status = finish_command(&ip);
 543                if (!status) {
 544                        reprepare_packed_git();
 545                        return NULL;
 546                }
 547                return "index-pack abnormal exit";
 548        }
 549}
 550
 551static void report(const char *unpack_status)
 552{
 553        struct command *cmd;
 554        packet_write(1, "unpack %s\n",
 555                     unpack_status ? unpack_status : "ok");
 556        for (cmd = commands; cmd; cmd = cmd->next) {
 557                if (!cmd->error_string)
 558                        packet_write(1, "ok %s\n",
 559                                     cmd->ref_name);
 560                else
 561                        packet_write(1, "ng %s %s\n",
 562                                     cmd->ref_name, cmd->error_string);
 563        }
 564        packet_flush(1);
 565}
 566
 567static int delete_only(struct command *cmd)
 568{
 569        while (cmd) {
 570                if (!is_null_sha1(cmd->new_sha1))
 571                        return 0;
 572                cmd = cmd->next;
 573        }
 574        return 1;
 575}
 576
 577static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
 578{
 579        char *other;
 580        size_t len;
 581        struct remote *remote;
 582        struct transport *transport;
 583        const struct ref *extra;
 584
 585        e->name[-1] = '\0';
 586        other = xstrdup(make_absolute_path(e->base));
 587        e->name[-1] = '/';
 588        len = strlen(other);
 589
 590        while (other[len-1] == '/')
 591                other[--len] = '\0';
 592        if (len < 8 || memcmp(other + len - 8, "/objects", 8))
 593                return 0;
 594        /* Is this a git repository with refs? */
 595        memcpy(other + len - 8, "/refs", 6);
 596        if (!is_directory(other))
 597                return 0;
 598        other[len - 8] = '\0';
 599        remote = remote_get(other);
 600        transport = transport_get(remote, other);
 601        for (extra = transport_get_remote_refs(transport);
 602             extra;
 603             extra = extra->next) {
 604                add_extra_ref(".have", extra->old_sha1, 0);
 605        }
 606        transport_disconnect(transport);
 607        free(other);
 608        return 0;
 609}
 610
 611static void add_alternate_refs(void)
 612{
 613        foreach_alt_odb(add_refs_from_alternate, NULL);
 614}
 615
 616int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 617{
 618        int advertise_refs = 0;
 619        int stateless_rpc = 0;
 620        int i;
 621        char *dir = NULL;
 622
 623        argv++;
 624        for (i = 1; i < argc; i++) {
 625                const char *arg = *argv++;
 626
 627                if (*arg == '-') {
 628                        if (!strcmp(arg, "--advertise-refs")) {
 629                                advertise_refs = 1;
 630                                continue;
 631                        }
 632                        if (!strcmp(arg, "--stateless-rpc")) {
 633                                stateless_rpc = 1;
 634                                continue;
 635                        }
 636
 637                        usage(receive_pack_usage);
 638                }
 639                if (dir)
 640                        usage(receive_pack_usage);
 641                dir = xstrdup(arg);
 642        }
 643        if (!dir)
 644                usage(receive_pack_usage);
 645
 646        setup_path();
 647
 648        if (!enter_repo(dir, 0))
 649                die("'%s' does not appear to be a git repository", dir);
 650
 651        if (is_repository_shallow())
 652                die("attempt to push into a shallow repository");
 653
 654        git_config(receive_pack_config, NULL);
 655
 656        if (0 <= transfer_unpack_limit)
 657                unpack_limit = transfer_unpack_limit;
 658        else if (0 <= receive_unpack_limit)
 659                unpack_limit = receive_unpack_limit;
 660
 661        capabilities_to_send = (prefer_ofs_delta) ?
 662                " report-status delete-refs ofs-delta " :
 663                " report-status delete-refs ";
 664
 665        if (advertise_refs || !stateless_rpc) {
 666                add_alternate_refs();
 667                write_head_info();
 668                clear_extra_refs();
 669
 670                /* EOF */
 671                packet_flush(1);
 672        }
 673        if (advertise_refs)
 674                return 0;
 675
 676        read_head_info();
 677        if (commands) {
 678                const char *unpack_status = NULL;
 679
 680                if (!delete_only(commands))
 681                        unpack_status = unpack();
 682                execute_commands(unpack_status);
 683                if (pack_lockfile)
 684                        unlink_or_warn(pack_lockfile);
 685                if (report_status)
 686                        report(unpack_status);
 687                run_receive_hook(post_receive_hook);
 688                run_update_post_hook(commands);
 689                if (auto_gc) {
 690                        const char *argv_gc_auto[] = {
 691                                "gc", "--auto", "--quiet", NULL,
 692                        };
 693                        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
 694                }
 695                if (auto_update_server_info)
 696                        update_server_info(0);
 697        }
 698        return 0;
 699}