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