receive-pack.con commit Fix refs.c;:repack_without_ref() clean-up path (26a063a)
   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 report_status;
  13
  14static char capabilities[] = "report-status";
  15static int capabilities_sent;
  16
  17static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  18{
  19        if (capabilities_sent)
  20                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
  21        else
  22                packet_write(1, "%s %s%c%s\n",
  23                             sha1_to_hex(sha1), path, 0, capabilities);
  24        capabilities_sent = 1;
  25        return 0;
  26}
  27
  28static void write_head_info(void)
  29{
  30        for_each_ref(show_ref, NULL);
  31        if (!capabilities_sent)
  32                show_ref("capabilities^{}", null_sha1, 0, NULL);
  33
  34}
  35
  36struct command {
  37        struct command *next;
  38        const char *error_string;
  39        unsigned char old_sha1[20];
  40        unsigned char new_sha1[20];
  41        char ref_name[FLEX_ARRAY]; /* more */
  42};
  43
  44static struct command *commands;
  45
  46static char update_hook[] = "hooks/update";
  47
  48static int run_update_hook(const char *refname,
  49                           char *old_hex, char *new_hex)
  50{
  51        int code;
  52
  53        if (access(update_hook, X_OK) < 0)
  54                return 0;
  55        code = run_command(update_hook, refname, old_hex, new_hex, NULL);
  56        switch (code) {
  57        case 0:
  58                return 0;
  59        case -ERR_RUN_COMMAND_FORK:
  60                return error("hook fork failed");
  61        case -ERR_RUN_COMMAND_EXEC:
  62                return error("hook execute failed");
  63        case -ERR_RUN_COMMAND_WAITPID:
  64                return error("waitpid failed");
  65        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
  66                return error("waitpid is confused");
  67        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
  68                return error("%s died of signal", update_hook);
  69        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
  70                return error("%s died strangely", update_hook);
  71        default:
  72                error("%s exited with error code %d", update_hook, -code);
  73                return -code;
  74        }
  75}
  76
  77static int update(struct command *cmd)
  78{
  79        const char *name = cmd->ref_name;
  80        unsigned char *old_sha1 = cmd->old_sha1;
  81        unsigned char *new_sha1 = cmd->new_sha1;
  82        char new_hex[41], old_hex[41];
  83        struct ref_lock *lock;
  84
  85        cmd->error_string = NULL;
  86        if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
  87                cmd->error_string = "funny refname";
  88                return error("refusing to create funny ref '%s' locally",
  89                             name);
  90        }
  91
  92        strcpy(new_hex, sha1_to_hex(new_sha1));
  93        strcpy(old_hex, sha1_to_hex(old_sha1));
  94        if (!has_sha1_file(new_sha1)) {
  95                cmd->error_string = "bad pack";
  96                return error("unpack should have generated %s, "
  97                             "but I can't find it!", new_hex);
  98        }
  99        if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
 100                struct commit *old_commit, *new_commit;
 101                struct commit_list *bases, *ent;
 102
 103                old_commit = (struct commit *)parse_object(old_sha1);
 104                new_commit = (struct commit *)parse_object(new_sha1);
 105                bases = get_merge_bases(old_commit, new_commit, 1);
 106                for (ent = bases; ent; ent = ent->next)
 107                        if (!hashcmp(old_sha1, ent->item->object.sha1))
 108                                break;
 109                free_commit_list(bases);
 110                if (!ent)
 111                        return error("denying non-fast forward;"
 112                                     " you should pull first");
 113        }
 114        if (run_update_hook(name, old_hex, new_hex)) {
 115                cmd->error_string = "hook declined";
 116                return error("hook declined to update %s", name);
 117        }
 118
 119        lock = lock_any_ref_for_update(name, old_sha1);
 120        if (!lock) {
 121                cmd->error_string = "failed to lock";
 122                return error("failed to lock %s", name);
 123        }
 124        write_ref_sha1(lock, new_sha1, "push");
 125
 126        fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 127        return 0;
 128}
 129
 130static char update_post_hook[] = "hooks/post-update";
 131
 132static void run_update_post_hook(struct command *cmd)
 133{
 134        struct command *cmd_p;
 135        int argc;
 136        const char **argv;
 137
 138        if (access(update_post_hook, X_OK) < 0)
 139                return;
 140        for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 141                if (cmd_p->error_string)
 142                        continue;
 143                argc++;
 144        }
 145        argv = xmalloc(sizeof(*argv) * (1 + argc));
 146        argv[0] = update_post_hook;
 147
 148        for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 149                char *p;
 150                if (cmd_p->error_string)
 151                        continue;
 152                p = xmalloc(strlen(cmd_p->ref_name) + 1);
 153                strcpy(p, cmd_p->ref_name);
 154                argv[argc] = p;
 155                argc++;
 156        }
 157        argv[argc] = NULL;
 158        run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
 159}
 160
 161/*
 162 * This gets called after(if) we've successfully
 163 * unpacked the data payload.
 164 */
 165static void execute_commands(void)
 166{
 167        struct command *cmd = commands;
 168
 169        while (cmd) {
 170                update(cmd);
 171                cmd = cmd->next;
 172        }
 173        run_update_post_hook(commands);
 174}
 175
 176static void read_head_info(void)
 177{
 178        struct command **p = &commands;
 179        for (;;) {
 180                static char line[1000];
 181                unsigned char old_sha1[20], new_sha1[20];
 182                struct command *cmd;
 183                char *refname;
 184                int len, reflen;
 185
 186                len = packet_read_line(0, line, sizeof(line));
 187                if (!len)
 188                        break;
 189                if (line[len-1] == '\n')
 190                        line[--len] = 0;
 191                if (len < 83 ||
 192                    line[40] != ' ' ||
 193                    line[81] != ' ' ||
 194                    get_sha1_hex(line, old_sha1) ||
 195                    get_sha1_hex(line + 41, new_sha1))
 196                        die("protocol error: expected old/new/ref, got '%s'",
 197                            line);
 198
 199                refname = line + 82;
 200                reflen = strlen(refname);
 201                if (reflen + 82 < len) {
 202                        if (strstr(refname + reflen + 1, "report-status"))
 203                                report_status = 1;
 204                }
 205                cmd = xmalloc(sizeof(struct command) + len - 80);
 206                hashcpy(cmd->old_sha1, old_sha1);
 207                hashcpy(cmd->new_sha1, new_sha1);
 208                memcpy(cmd->ref_name, line + 82, len - 81);
 209                cmd->error_string = "n/a (unpacker error)";
 210                cmd->next = NULL;
 211                *p = cmd;
 212                p = &cmd->next;
 213        }
 214}
 215
 216static const char *unpack(int *error_code)
 217{
 218        int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
 219
 220        *error_code = 0;
 221        switch (code) {
 222        case 0:
 223                return NULL;
 224        case -ERR_RUN_COMMAND_FORK:
 225                return "unpack fork failed";
 226        case -ERR_RUN_COMMAND_EXEC:
 227                return "unpack execute failed";
 228        case -ERR_RUN_COMMAND_WAITPID:
 229                return "waitpid failed";
 230        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 231                return "waitpid is confused";
 232        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 233                return "unpacker died of signal";
 234        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 235                return "unpacker died strangely";
 236        default:
 237                *error_code = -code;
 238                return "unpacker exited with error code";
 239        }
 240}
 241
 242static void report(const char *unpack_status)
 243{
 244        struct command *cmd;
 245        packet_write(1, "unpack %s\n",
 246                     unpack_status ? unpack_status : "ok");
 247        for (cmd = commands; cmd; cmd = cmd->next) {
 248                if (!cmd->error_string)
 249                        packet_write(1, "ok %s\n",
 250                                     cmd->ref_name);
 251                else
 252                        packet_write(1, "ng %s %s\n",
 253                                     cmd->ref_name, cmd->error_string);
 254        }
 255        packet_flush(1);
 256}
 257
 258int main(int argc, char **argv)
 259{
 260        int i;
 261        char *dir = NULL;
 262
 263        argv++;
 264        for (i = 1; i < argc; i++) {
 265                char *arg = *argv++;
 266
 267                if (*arg == '-') {
 268                        /* Do flag handling here */
 269                        usage(receive_pack_usage);
 270                }
 271                if (dir)
 272                        usage(receive_pack_usage);
 273                dir = arg;
 274        }
 275        if (!dir)
 276                usage(receive_pack_usage);
 277
 278        if (!enter_repo(dir, 0))
 279                die("'%s': unable to chdir or not a git archive", dir);
 280
 281        setup_ident();
 282        git_config(git_default_config);
 283
 284        write_head_info();
 285
 286        /* EOF */
 287        packet_flush(1);
 288
 289        read_head_info();
 290        if (commands) {
 291                int code;
 292                const char *unpack_status = unpack(&code);
 293                if (!unpack_status)
 294                        execute_commands();
 295                if (report_status)
 296                        report(unpack_status);
 297        }
 298        return 0;
 299}