receive-pack.con commit Move deny_non_fast_forwards handling completely into receive-pack. (6fb75be)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include "run-command.h"
   5#include "commit.h"
   6#include "object.h"
   7
   8static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
   9
  10static const char *unpacker[] = { "unpack-objects", NULL };
  11
  12static int deny_non_fast_forwards = 0;
  13static int report_status;
  14
  15static char capabilities[] = "report-status";
  16static int capabilities_sent;
  17
  18static int receive_pack_config(const char *var, const char *value)
  19{
  20        git_default_config(var, value);
  21
  22        if (strcmp(var, "receive.denynonfastforwards") == 0)
  23        {
  24                deny_non_fast_forwards = git_config_bool(var, value);
  25                return 0;
  26        }
  27
  28        return 0;
  29}
  30
  31static int show_ref(const char *path, const unsigned char *sha1)
  32{
  33        if (capabilities_sent)
  34                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
  35        else
  36                packet_write(1, "%s %s%c%s\n",
  37                             sha1_to_hex(sha1), path, 0, capabilities);
  38        capabilities_sent = 1;
  39        return 0;
  40}
  41
  42static void write_head_info(void)
  43{
  44        for_each_ref(show_ref);
  45        if (!capabilities_sent)
  46                show_ref("capabilities^{}", null_sha1);
  47
  48}
  49
  50struct command {
  51        struct command *next;
  52        const char *error_string;
  53        unsigned char old_sha1[20];
  54        unsigned char new_sha1[20];
  55        char ref_name[FLEX_ARRAY]; /* more */
  56};
  57
  58static struct command *commands;
  59
  60static int is_all_zeroes(const char *hex)
  61{
  62        int i;
  63        for (i = 0; i < 40; i++)
  64                if (*hex++ != '0')
  65                        return 0;
  66        return 1;
  67}
  68
  69static int verify_old_ref(const char *name, char *hex_contents)
  70{
  71        int fd, ret;
  72        char buffer[60];
  73
  74        if (is_all_zeroes(hex_contents))
  75                return 0;
  76        fd = open(name, O_RDONLY);
  77        if (fd < 0)
  78                return -1;
  79        ret = read(fd, buffer, 40);
  80        close(fd);
  81        if (ret != 40)
  82                return -1;
  83        if (memcmp(buffer, hex_contents, 40))
  84                return -1;
  85        return 0;
  86}
  87
  88static char update_hook[] = "hooks/update";
  89
  90static int run_update_hook(const char *refname,
  91                           char *old_hex, char *new_hex)
  92{
  93        int code;
  94
  95        if (access(update_hook, X_OK) < 0)
  96                return 0;
  97        code = run_command(update_hook, refname, old_hex, new_hex, NULL);
  98        switch (code) {
  99        case 0:
 100                return 0;
 101        case -ERR_RUN_COMMAND_FORK:
 102                return error("hook fork failed");
 103        case -ERR_RUN_COMMAND_EXEC:
 104                return error("hook execute failed");
 105        case -ERR_RUN_COMMAND_WAITPID:
 106                return error("waitpid failed");
 107        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 108                return error("waitpid is confused");
 109        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 110                return error("%s died of signal", update_hook);
 111        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 112                return error("%s died strangely", update_hook);
 113        default:
 114                error("%s exited with error code %d", update_hook, -code);
 115                return -code;
 116        }
 117}
 118
 119static int update(struct command *cmd)
 120{
 121        const char *name = cmd->ref_name;
 122        unsigned char *old_sha1 = cmd->old_sha1;
 123        unsigned char *new_sha1 = cmd->new_sha1;
 124        char new_hex[60], *old_hex, *lock_name;
 125        int newfd, namelen, written;
 126
 127        cmd->error_string = NULL;
 128        if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
 129                cmd->error_string = "funny refname";
 130                return error("refusing to create funny ref '%s' locally",
 131                             name);
 132        }
 133
 134        namelen = strlen(name);
 135        lock_name = xmalloc(namelen + 10);
 136        memcpy(lock_name, name, namelen);
 137        memcpy(lock_name + namelen, ".lock", 6);
 138
 139        strcpy(new_hex, sha1_to_hex(new_sha1));
 140        old_hex = sha1_to_hex(old_sha1);
 141        if (!has_sha1_file(new_sha1)) {
 142                cmd->error_string = "bad pack";
 143                return error("unpack should have generated %s, "
 144                             "but I can't find it!", new_hex);
 145        }
 146        if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
 147                struct commit *old_commit, *new_commit;
 148                struct commit_list *bases, *ent;
 149
 150                old_commit = (struct commit *)parse_object(old_sha1);
 151                new_commit = (struct commit *)parse_object(new_sha1);
 152                bases = get_merge_bases(old_commit, new_commit, 1);
 153                for (ent = bases; ent; ent = ent->next)
 154                        if (!hashcmp(old_sha1, ent->item->object.sha1))
 155                                break;
 156                free_commit_list(bases);
 157                if (!ent)
 158                        return error("denying non-fast forward;"
 159                                     " you should pull first");
 160        }
 161        safe_create_leading_directories(lock_name);
 162
 163        newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
 164        if (newfd < 0) {
 165                cmd->error_string = "can't lock";
 166                return error("unable to create %s (%s)",
 167                             lock_name, strerror(errno));
 168        }
 169
 170        /* Write the ref with an ending '\n' */
 171        new_hex[40] = '\n';
 172        new_hex[41] = 0;
 173        written = write(newfd, new_hex, 41);
 174        /* Remove the '\n' again */
 175        new_hex[40] = 0;
 176
 177        close(newfd);
 178        if (written != 41) {
 179                unlink(lock_name);
 180                cmd->error_string = "can't write";
 181                return error("unable to write %s", lock_name);
 182        }
 183        if (verify_old_ref(name, old_hex) < 0) {
 184                unlink(lock_name);
 185                cmd->error_string = "raced";
 186                return error("%s changed during push", name);
 187        }
 188        if (run_update_hook(name, old_hex, new_hex)) {
 189                unlink(lock_name);
 190                cmd->error_string = "hook declined";
 191                return error("hook declined to update %s", name);
 192        }
 193        else if (rename(lock_name, name) < 0) {
 194                unlink(lock_name);
 195                cmd->error_string = "can't rename";
 196                return error("unable to replace %s", name);
 197        }
 198        else {
 199                fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 200                return 0;
 201        }
 202}
 203
 204static char update_post_hook[] = "hooks/post-update";
 205
 206static void run_update_post_hook(struct command *cmd)
 207{
 208        struct command *cmd_p;
 209        int argc;
 210        const char **argv;
 211
 212        if (access(update_post_hook, X_OK) < 0)
 213                return;
 214        for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 215                if (cmd_p->error_string)
 216                        continue;
 217                argc++;
 218        }
 219        argv = xmalloc(sizeof(*argv) * (1 + argc));
 220        argv[0] = update_post_hook;
 221
 222        for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 223                char *p;
 224                if (cmd_p->error_string)
 225                        continue;
 226                p = xmalloc(strlen(cmd_p->ref_name) + 1);
 227                strcpy(p, cmd_p->ref_name);
 228                argv[argc] = p;
 229                argc++;
 230        }
 231        argv[argc] = NULL;
 232        run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
 233}
 234
 235/*
 236 * This gets called after(if) we've successfully
 237 * unpacked the data payload.
 238 */
 239static void execute_commands(void)
 240{
 241        struct command *cmd = commands;
 242
 243        while (cmd) {
 244                update(cmd);
 245                cmd = cmd->next;
 246        }
 247        run_update_post_hook(commands);
 248}
 249
 250static void read_head_info(void)
 251{
 252        struct command **p = &commands;
 253        for (;;) {
 254                static char line[1000];
 255                unsigned char old_sha1[20], new_sha1[20];
 256                struct command *cmd;
 257                char *refname;
 258                int len, reflen;
 259
 260                len = packet_read_line(0, line, sizeof(line));
 261                if (!len)
 262                        break;
 263                if (line[len-1] == '\n')
 264                        line[--len] = 0;
 265                if (len < 83 ||
 266                    line[40] != ' ' ||
 267                    line[81] != ' ' ||
 268                    get_sha1_hex(line, old_sha1) ||
 269                    get_sha1_hex(line + 41, new_sha1))
 270                        die("protocol error: expected old/new/ref, got '%s'",
 271                            line);
 272
 273                refname = line + 82;
 274                reflen = strlen(refname);
 275                if (reflen + 82 < len) {
 276                        if (strstr(refname + reflen + 1, "report-status"))
 277                                report_status = 1;
 278                }
 279                cmd = xmalloc(sizeof(struct command) + len - 80);
 280                hashcpy(cmd->old_sha1, old_sha1);
 281                hashcpy(cmd->new_sha1, new_sha1);
 282                memcpy(cmd->ref_name, line + 82, len - 81);
 283                cmd->error_string = "n/a (unpacker error)";
 284                cmd->next = NULL;
 285                *p = cmd;
 286                p = &cmd->next;
 287        }
 288}
 289
 290static const char *unpack(int *error_code)
 291{
 292        int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
 293
 294        *error_code = 0;
 295        switch (code) {
 296        case 0:
 297                return NULL;
 298        case -ERR_RUN_COMMAND_FORK:
 299                return "unpack fork failed";
 300        case -ERR_RUN_COMMAND_EXEC:
 301                return "unpack execute failed";
 302        case -ERR_RUN_COMMAND_WAITPID:
 303                return "waitpid failed";
 304        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 305                return "waitpid is confused";
 306        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 307                return "unpacker died of signal";
 308        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 309                return "unpacker died strangely";
 310        default:
 311                *error_code = -code;
 312                return "unpacker exited with error code";
 313        }
 314}
 315
 316static void report(const char *unpack_status)
 317{
 318        struct command *cmd;
 319        packet_write(1, "unpack %s\n",
 320                     unpack_status ? unpack_status : "ok");
 321        for (cmd = commands; cmd; cmd = cmd->next) {
 322                if (!cmd->error_string)
 323                        packet_write(1, "ok %s\n",
 324                                     cmd->ref_name);
 325                else
 326                        packet_write(1, "ng %s %s\n",
 327                                     cmd->ref_name, cmd->error_string);
 328        }
 329        packet_flush(1);
 330}
 331
 332int main(int argc, char **argv)
 333{
 334        int i;
 335        char *dir = NULL;
 336
 337        argv++;
 338        for (i = 1; i < argc; i++) {
 339                char *arg = *argv++;
 340
 341                if (*arg == '-') {
 342                        /* Do flag handling here */
 343                        usage(receive_pack_usage);
 344                }
 345                if (dir)
 346                        usage(receive_pack_usage);
 347                dir = arg;
 348        }
 349        if (!dir)
 350                usage(receive_pack_usage);
 351
 352        if(!enter_repo(dir, 0))
 353                die("'%s': unable to chdir or not a git archive", dir);
 354
 355        git_config(receive_pack_config);
 356
 357        write_head_info();
 358
 359        /* EOF */
 360        packet_flush(1);
 361
 362        read_head_info();
 363        if (commands) {
 364                int code;
 365                const char *unpack_status = unpack(&code);
 366                if (!unpack_status)
 367                        execute_commands();
 368                if (report_status)
 369                        report(unpack_status);
 370        }
 371        return 0;
 372}