builtin-receive-pack.con commit Refuse deleting the current branch via push (375881f)
   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 const char *head_name;
  32static char *capabilities_to_send;
  33
  34static enum deny_action parse_deny_action(const char *var, const char *value)
  35{
  36        if (value) {
  37                if (!strcasecmp(value, "ignore"))
  38                        return DENY_IGNORE;
  39                if (!strcasecmp(value, "warn"))
  40                        return DENY_WARN;
  41                if (!strcasecmp(value, "refuse"))
  42                        return DENY_REFUSE;
  43        }
  44        if (git_config_bool(var, value))
  45                return DENY_REFUSE;
  46        return DENY_IGNORE;
  47}
  48
  49static int receive_pack_config(const char *var, const char *value, void *cb)
  50{
  51        if (strcmp(var, "receive.denydeletes") == 0) {
  52                deny_deletes = git_config_bool(var, value);
  53                return 0;
  54        }
  55
  56        if (strcmp(var, "receive.denynonfastforwards") == 0) {
  57                deny_non_fast_forwards = git_config_bool(var, value);
  58                return 0;
  59        }
  60
  61        if (strcmp(var, "receive.unpacklimit") == 0) {
  62                receive_unpack_limit = git_config_int(var, value);
  63                return 0;
  64        }
  65
  66        if (strcmp(var, "transfer.unpacklimit") == 0) {
  67                transfer_unpack_limit = git_config_int(var, value);
  68                return 0;
  69        }
  70
  71        if (strcmp(var, "receive.fsckobjects") == 0) {
  72                receive_fsck_objects = git_config_bool(var, value);
  73                return 0;
  74        }
  75
  76        if (!strcmp(var, "receive.denycurrentbranch")) {
  77                deny_current_branch = parse_deny_action(var, value);
  78                return 0;
  79        }
  80
  81        if (strcmp(var, "receive.denydeletecurrent") == 0) {
  82                deny_delete_current = parse_deny_action(var, value);
  83                return 0;
  84        }
  85
  86        if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
  87                prefer_ofs_delta = git_config_bool(var, value);
  88                return 0;
  89        }
  90
  91        return git_default_config(var, value, cb);
  92}
  93
  94static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  95{
  96        if (!capabilities_to_send)
  97                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
  98        else
  99                packet_write(1, "%s %s%c%s\n",
 100                             sha1_to_hex(sha1), path, 0, capabilities_to_send);
 101        capabilities_to_send = NULL;
 102        return 0;
 103}
 104
 105static void write_head_info(void)
 106{
 107        for_each_ref(show_ref, NULL);
 108        if (capabilities_to_send)
 109                show_ref("capabilities^{}", null_sha1, 0, NULL);
 110
 111}
 112
 113struct command {
 114        struct command *next;
 115        const char *error_string;
 116        unsigned char old_sha1[20];
 117        unsigned char new_sha1[20];
 118        char ref_name[FLEX_ARRAY]; /* more */
 119};
 120
 121static struct command *commands;
 122
 123static const char pre_receive_hook[] = "hooks/pre-receive";
 124static const char post_receive_hook[] = "hooks/post-receive";
 125
 126static int run_status(int code, const char *cmd_name)
 127{
 128        switch (code) {
 129        case 0:
 130                return 0;
 131        case -ERR_RUN_COMMAND_FORK:
 132                return error("fork of %s failed", cmd_name);
 133        case -ERR_RUN_COMMAND_EXEC:
 134                return error("execute of %s failed", cmd_name);
 135        case -ERR_RUN_COMMAND_PIPE:
 136                return error("pipe failed");
 137        case -ERR_RUN_COMMAND_WAITPID:
 138                return error("waitpid failed");
 139        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 140                return error("waitpid is confused");
 141        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 142                return error("%s died of signal", cmd_name);
 143        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 144                return error("%s died strangely", cmd_name);
 145        default:
 146                error("%s exited with error code %d", cmd_name, -code);
 147                return -code;
 148        }
 149}
 150
 151static int run_receive_hook(const char *hook_name)
 152{
 153        static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
 154        struct command *cmd;
 155        struct child_process proc;
 156        const char *argv[2];
 157        int have_input = 0, code;
 158
 159        for (cmd = commands; !have_input && cmd; cmd = cmd->next) {
 160                if (!cmd->error_string)
 161                        have_input = 1;
 162        }
 163
 164        if (!have_input || access(hook_name, X_OK) < 0)
 165                return 0;
 166
 167        argv[0] = hook_name;
 168        argv[1] = NULL;
 169
 170        memset(&proc, 0, sizeof(proc));
 171        proc.argv = argv;
 172        proc.in = -1;
 173        proc.stdout_to_stderr = 1;
 174
 175        code = start_command(&proc);
 176        if (code)
 177                return run_status(code, hook_name);
 178        for (cmd = commands; cmd; cmd = cmd->next) {
 179                if (!cmd->error_string) {
 180                        size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
 181                                sha1_to_hex(cmd->old_sha1),
 182                                sha1_to_hex(cmd->new_sha1),
 183                                cmd->ref_name);
 184                        if (write_in_full(proc.in, buf, n) != n)
 185                                break;
 186                }
 187        }
 188        close(proc.in);
 189        return run_status(finish_command(&proc), hook_name);
 190}
 191
 192static int run_update_hook(struct command *cmd)
 193{
 194        static const char update_hook[] = "hooks/update";
 195        const char *argv[5];
 196
 197        if (access(update_hook, X_OK) < 0)
 198                return 0;
 199
 200        argv[0] = update_hook;
 201        argv[1] = cmd->ref_name;
 202        argv[2] = sha1_to_hex(cmd->old_sha1);
 203        argv[3] = sha1_to_hex(cmd->new_sha1);
 204        argv[4] = NULL;
 205
 206        return run_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
 207                                        RUN_COMMAND_STDOUT_TO_STDERR),
 208                        update_hook);
 209}
 210
 211static int is_ref_checked_out(const char *ref)
 212{
 213        if (is_bare_repository())
 214                return 0;
 215
 216        if (!head_name)
 217                return 0;
 218        return !strcmp(head_name, ref);
 219}
 220
 221static char *refuse_unconfigured_deny_msg[] = {
 222        "By default, updating the current branch in a non-bare repository",
 223        "is denied, because it will make the index and work tree inconsistent",
 224        "with what you pushed, and will require 'git reset --hard' to match",
 225        "the work tree to HEAD.",
 226        "",
 227        "You can set 'receive.denyCurrentBranch' configuration variable to",
 228        "'ignore' or 'warn' in the remote repository to allow pushing into",
 229        "its current branch; however, this is not recommended unless you",
 230        "arranged to update its work tree to match what you pushed in some",
 231        "other way.",
 232        "",
 233        "To squelch this message and still keep the default behaviour, set",
 234        "'receive.denyCurrentBranch' configuration variable to 'refuse'."
 235};
 236
 237static void refuse_unconfigured_deny(void)
 238{
 239        int i;
 240        for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
 241                error("%s", refuse_unconfigured_deny_msg[i]);
 242}
 243
 244static char *refuse_unconfigured_deny_delete_current_msg[] = {
 245        "By default, deleting the current branch is denied, because the next",
 246        "'git clone' won't result in any file checked out, causing confusion.",
 247        "",
 248        "You can set 'receive.denyDeleteCurrent' configuration variable to",
 249        "'warn' or 'ignore' in the remote repository to allow deleting the",
 250        "current branch, with or without a warning message.",
 251        "",
 252        "To squelch this message, you can set it to 'refuse'."
 253};
 254
 255static void refuse_unconfigured_deny_delete_current(void)
 256{
 257        int i;
 258        for (i = 0;
 259             i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
 260             i++)
 261                error("%s", refuse_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_WARN:
 282                        warning("updating the current branch");
 283                        break;
 284                case DENY_REFUSE:
 285                case DENY_UNCONFIGURED:
 286                        error("refusing to update checked out branch: %s", name);
 287                        if (deny_current_branch == DENY_UNCONFIGURED)
 288                                refuse_unconfigured_deny();
 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                                warning("deleting the current branch");
 311                                break;
 312                        case DENY_REFUSE:
 313                        case DENY_UNCONFIGURED:
 314                                if (deny_delete_current == DENY_UNCONFIGURED)
 315                                        refuse_unconfigured_deny_delete_current();
 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        run_status(status, update_post_hook);
 411}
 412
 413static void execute_commands(const char *unpacker_error)
 414{
 415        struct command *cmd = commands;
 416        unsigned char sha1[20];
 417
 418        if (unpacker_error) {
 419                while (cmd) {
 420                        cmd->error_string = "n/a (unpacker error)";
 421                        cmd = cmd->next;
 422                }
 423                return;
 424        }
 425
 426        if (run_receive_hook(pre_receive_hook)) {
 427                while (cmd) {
 428                        cmd->error_string = "pre-receive hook declined";
 429                        cmd = cmd->next;
 430                }
 431                return;
 432        }
 433
 434        head_name = resolve_ref("HEAD", sha1, 0, NULL);
 435
 436        while (cmd) {
 437                cmd->error_string = update(cmd);
 438                cmd = cmd->next;
 439        }
 440}
 441
 442static void read_head_info(void)
 443{
 444        struct command **p = &commands;
 445        for (;;) {
 446                static char line[1000];
 447                unsigned char old_sha1[20], new_sha1[20];
 448                struct command *cmd;
 449                char *refname;
 450                int len, reflen;
 451
 452                len = packet_read_line(0, line, sizeof(line));
 453                if (!len)
 454                        break;
 455                if (line[len-1] == '\n')
 456                        line[--len] = 0;
 457                if (len < 83 ||
 458                    line[40] != ' ' ||
 459                    line[81] != ' ' ||
 460                    get_sha1_hex(line, old_sha1) ||
 461                    get_sha1_hex(line + 41, new_sha1))
 462                        die("protocol error: expected old/new/ref, got '%s'",
 463                            line);
 464
 465                refname = line + 82;
 466                reflen = strlen(refname);
 467                if (reflen + 82 < len) {
 468                        if (strstr(refname + reflen + 1, "report-status"))
 469                                report_status = 1;
 470                }
 471                cmd = xmalloc(sizeof(struct command) + len - 80);
 472                hashcpy(cmd->old_sha1, old_sha1);
 473                hashcpy(cmd->new_sha1, new_sha1);
 474                memcpy(cmd->ref_name, line + 82, len - 81);
 475                cmd->error_string = NULL;
 476                cmd->next = NULL;
 477                *p = cmd;
 478                p = &cmd->next;
 479        }
 480}
 481
 482static const char *parse_pack_header(struct pack_header *hdr)
 483{
 484        switch (read_pack_header(0, hdr)) {
 485        case PH_ERROR_EOF:
 486                return "eof before pack header was fully read";
 487
 488        case PH_ERROR_PACK_SIGNATURE:
 489                return "protocol error (pack signature mismatch detected)";
 490
 491        case PH_ERROR_PROTOCOL:
 492                return "protocol error (pack version unsupported)";
 493
 494        default:
 495                return "unknown error in parse_pack_header";
 496
 497        case 0:
 498                return NULL;
 499        }
 500}
 501
 502static const char *pack_lockfile;
 503
 504static const char *unpack(void)
 505{
 506        struct pack_header hdr;
 507        const char *hdr_err;
 508        char hdr_arg[38];
 509
 510        hdr_err = parse_pack_header(&hdr);
 511        if (hdr_err)
 512                return hdr_err;
 513        snprintf(hdr_arg, sizeof(hdr_arg),
 514                        "--pack_header=%"PRIu32",%"PRIu32,
 515                        ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
 516
 517        if (ntohl(hdr.hdr_entries) < unpack_limit) {
 518                int code, i = 0;
 519                const char *unpacker[4];
 520                unpacker[i++] = "unpack-objects";
 521                if (receive_fsck_objects)
 522                        unpacker[i++] = "--strict";
 523                unpacker[i++] = hdr_arg;
 524                unpacker[i++] = NULL;
 525                code = run_command_v_opt(unpacker, RUN_GIT_CMD);
 526                if (!code)
 527                        return NULL;
 528                run_status(code, unpacker[0]);
 529                return "unpack-objects abnormal exit";
 530        } else {
 531                const char *keeper[7];
 532                int s, status, i = 0;
 533                char keep_arg[256];
 534                struct child_process ip;
 535
 536                s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid());
 537                if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
 538                        strcpy(keep_arg + s, "localhost");
 539
 540                keeper[i++] = "index-pack";
 541                keeper[i++] = "--stdin";
 542                if (receive_fsck_objects)
 543                        keeper[i++] = "--strict";
 544                keeper[i++] = "--fix-thin";
 545                keeper[i++] = hdr_arg;
 546                keeper[i++] = keep_arg;
 547                keeper[i++] = NULL;
 548                memset(&ip, 0, sizeof(ip));
 549                ip.argv = keeper;
 550                ip.out = -1;
 551                ip.git_cmd = 1;
 552                status = start_command(&ip);
 553                if (status) {
 554                        run_status(status, keeper[0]);
 555                        return "index-pack fork failed";
 556                }
 557                pack_lockfile = index_pack_lockfile(ip.out);
 558                close(ip.out);
 559                status = finish_command(&ip);
 560                if (!status) {
 561                        reprepare_packed_git();
 562                        return NULL;
 563                }
 564                run_status(status, keeper[0]);
 565                return "index-pack abnormal exit";
 566        }
 567}
 568
 569static void report(const char *unpack_status)
 570{
 571        struct command *cmd;
 572        packet_write(1, "unpack %s\n",
 573                     unpack_status ? unpack_status : "ok");
 574        for (cmd = commands; cmd; cmd = cmd->next) {
 575                if (!cmd->error_string)
 576                        packet_write(1, "ok %s\n",
 577                                     cmd->ref_name);
 578                else
 579                        packet_write(1, "ng %s %s\n",
 580                                     cmd->ref_name, cmd->error_string);
 581        }
 582        packet_flush(1);
 583}
 584
 585static int delete_only(struct command *cmd)
 586{
 587        while (cmd) {
 588                if (!is_null_sha1(cmd->new_sha1))
 589                        return 0;
 590                cmd = cmd->next;
 591        }
 592        return 1;
 593}
 594
 595static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
 596{
 597        char *other;
 598        size_t len;
 599        struct remote *remote;
 600        struct transport *transport;
 601        const struct ref *extra;
 602
 603        e->name[-1] = '\0';
 604        other = xstrdup(make_absolute_path(e->base));
 605        e->name[-1] = '/';
 606        len = strlen(other);
 607
 608        while (other[len-1] == '/')
 609                other[--len] = '\0';
 610        if (len < 8 || memcmp(other + len - 8, "/objects", 8))
 611                return 0;
 612        /* Is this a git repository with refs? */
 613        memcpy(other + len - 8, "/refs", 6);
 614        if (!is_directory(other))
 615                return 0;
 616        other[len - 8] = '\0';
 617        remote = remote_get(other);
 618        transport = transport_get(remote, other);
 619        for (extra = transport_get_remote_refs(transport);
 620             extra;
 621             extra = extra->next) {
 622                add_extra_ref(".have", extra->old_sha1, 0);
 623        }
 624        transport_disconnect(transport);
 625        free(other);
 626        return 0;
 627}
 628
 629static void add_alternate_refs(void)
 630{
 631        foreach_alt_odb(add_refs_from_alternate, NULL);
 632}
 633
 634int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 635{
 636        int i;
 637        char *dir = NULL;
 638
 639        argv++;
 640        for (i = 1; i < argc; i++) {
 641                const char *arg = *argv++;
 642
 643                if (*arg == '-') {
 644                        /* Do flag handling here */
 645                        usage(receive_pack_usage);
 646                }
 647                if (dir)
 648                        usage(receive_pack_usage);
 649                dir = xstrdup(arg);
 650        }
 651        if (!dir)
 652                usage(receive_pack_usage);
 653
 654        setup_path();
 655
 656        if (!enter_repo(dir, 0))
 657                die("'%s' does not appear to be a git repository", dir);
 658
 659        if (is_repository_shallow())
 660                die("attempt to push into a shallow repository");
 661
 662        git_config(receive_pack_config, NULL);
 663
 664        if (0 <= transfer_unpack_limit)
 665                unpack_limit = transfer_unpack_limit;
 666        else if (0 <= receive_unpack_limit)
 667                unpack_limit = receive_unpack_limit;
 668
 669        capabilities_to_send = (prefer_ofs_delta) ?
 670                " report-status delete-refs ofs-delta " :
 671                " report-status delete-refs ";
 672
 673        add_alternate_refs();
 674        write_head_info();
 675        clear_extra_refs();
 676
 677        /* EOF */
 678        packet_flush(1);
 679
 680        read_head_info();
 681        if (commands) {
 682                const char *unpack_status = NULL;
 683
 684                if (!delete_only(commands))
 685                        unpack_status = unpack();
 686                execute_commands(unpack_status);
 687                if (pack_lockfile)
 688                        unlink_or_warn(pack_lockfile);
 689                if (report_status)
 690                        report(unpack_status);
 691                run_receive_hook(post_receive_hook);
 692                run_update_post_hook(commands);
 693        }
 694        return 0;
 695}