receive-pack.con commit [PATCH] Fix warning about non-void return in a void function. (c742b81)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include "run-command.h"
   5#include <sys/wait.h>
   6
   7static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
   8
   9static const char unpacker[] = "git-unpack-objects";
  10
  11static int show_ref(const char *path, const unsigned char *sha1)
  12{
  13        packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
  14        return 0;
  15}
  16
  17static void write_head_info(void)
  18{
  19        for_each_ref(show_ref);
  20}
  21
  22struct command {
  23        struct command *next;
  24        unsigned char old_sha1[20];
  25        unsigned char new_sha1[20];
  26        char ref_name[0];
  27};
  28
  29static struct command *commands = NULL;
  30
  31static int is_all_zeroes(const char *hex)
  32{
  33        int i;
  34        for (i = 0; i < 40; i++)
  35                if (*hex++ != '0')
  36                        return 0;
  37        return 1;
  38}
  39
  40static int verify_old_ref(const char *name, char *hex_contents)
  41{
  42        int fd, ret;
  43        char buffer[60];
  44
  45        if (is_all_zeroes(hex_contents))
  46                return 0;
  47        fd = open(name, O_RDONLY);
  48        if (fd < 0)
  49                return -1;
  50        ret = read(fd, buffer, 40);
  51        close(fd);
  52        if (ret != 40)
  53                return -1;
  54        if (memcmp(buffer, hex_contents, 40))
  55                return -1;
  56        return 0;
  57}
  58
  59static char update_hook[] = "hooks/update";
  60
  61static int run_update_hook(const char *refname,
  62                           char *old_hex, char *new_hex)
  63{
  64        int code;
  65
  66        if (access(update_hook, X_OK) < 0)
  67                return 0;
  68        code = run_command(update_hook, refname, old_hex, new_hex, NULL);
  69        switch (code) {
  70        case 0:
  71                return 0;
  72        case -ERR_RUN_COMMAND_FORK:
  73                die("hook fork failed");
  74        case -ERR_RUN_COMMAND_EXEC:
  75                die("hook execute failed");
  76        case -ERR_RUN_COMMAND_WAITPID:
  77                die("waitpid failed");
  78        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
  79                die("waitpid is confused");
  80        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
  81                fprintf(stderr, "%s died of signal", update_hook);
  82                return -1;
  83        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
  84                die("%s died strangely", update_hook);
  85        default:
  86                error("%s exited with error code %d", update_hook, -code);
  87                return -code;
  88        }
  89}
  90
  91static void update(const char *name, unsigned char *old_sha1, unsigned char *new_sha1)
  92{
  93        char new_hex[60], *old_hex, *lock_name;
  94        int newfd, namelen, written;
  95
  96        namelen = strlen(name);
  97        lock_name = xmalloc(namelen + 10);
  98        memcpy(lock_name, name, namelen);
  99        memcpy(lock_name + namelen, ".lock", 6);
 100
 101        strcpy(new_hex, sha1_to_hex(new_sha1));
 102        old_hex = sha1_to_hex(old_sha1);
 103        if (!has_sha1_file(new_sha1))
 104                die("unpack should have generated %s, but I can't find it!", new_hex);
 105
 106        newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
 107        if (newfd < 0)
 108                die("unable to create %s (%s)", lock_name, strerror(errno));
 109
 110        /* Write the ref with an ending '\n' */
 111        new_hex[40] = '\n';
 112        new_hex[41] = 0;
 113        written = write(newfd, new_hex, 41);
 114        /* Remove the '\n' again */
 115        new_hex[40] = 0;
 116
 117        close(newfd);
 118        if (written != 41) {
 119                unlink(lock_name);
 120                die("unable to write %s", lock_name);
 121        }
 122        if (verify_old_ref(name, old_hex) < 0) {
 123                unlink(lock_name);
 124                die("%s changed during push", name);
 125        }
 126        if (run_update_hook(name, old_hex, new_hex)) {
 127                unlink(lock_name);
 128                fprintf(stderr, "hook declined to update %s\n", name);
 129        }
 130        else if (rename(lock_name, name) < 0) {
 131                unlink(lock_name);
 132                die("unable to replace %s", name);
 133        }
 134        else
 135                fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 136}
 137
 138
 139/*
 140 * This gets called after(if) we've successfully
 141 * unpacked the data payload.
 142 */
 143static void execute_commands(void)
 144{
 145        struct command *cmd = commands;
 146
 147        while (cmd) {
 148                update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
 149                cmd = cmd->next;
 150        }
 151        run_update_hook("", NULL, NULL);
 152}
 153
 154static void read_head_info(void)
 155{
 156        struct command **p = &commands;
 157        for (;;) {
 158                static char line[1000];
 159                unsigned char old_sha1[20], new_sha1[20];
 160                struct command *cmd;
 161                int len;
 162
 163                len = packet_read_line(0, line, sizeof(line));
 164                if (!len)
 165                        break;
 166                if (line[len-1] == '\n')
 167                        line[--len] = 0;
 168                if (len < 83 ||
 169                    line[40] != ' ' ||
 170                    line[81] != ' ' ||
 171                    get_sha1_hex(line, old_sha1) ||
 172                    get_sha1_hex(line + 41, new_sha1))
 173                        die("protocol error: expected old/new/ref, got '%s'", line);
 174                cmd = xmalloc(sizeof(struct command) + len - 80);
 175                memcpy(cmd->old_sha1, old_sha1, 20);
 176                memcpy(cmd->new_sha1, new_sha1, 20);
 177                memcpy(cmd->ref_name, line + 82, len - 81);
 178                cmd->next = NULL;
 179                *p = cmd;
 180                p = &cmd->next;
 181        }
 182}
 183
 184static void unpack(void)
 185{
 186        int code = run_command(unpacker, NULL);
 187        switch (code) {
 188        case 0:
 189                return;
 190        case -ERR_RUN_COMMAND_FORK:
 191                die("unpack fork failed");
 192        case -ERR_RUN_COMMAND_EXEC:
 193                die("unpack execute failed");
 194        case -ERR_RUN_COMMAND_WAITPID:
 195                die("waitpid failed");
 196        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 197                die("waitpid is confused");
 198        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 199                die("%s died of signal", unpacker);
 200        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 201                die("%s died strangely", unpacker);
 202        default:
 203                die("%s exited with error code %d", unpacker, -code);
 204        }
 205}
 206
 207int main(int argc, char **argv)
 208{
 209        int i;
 210        const char *dir = NULL;
 211
 212        argv++;
 213        for (i = 1; i < argc; i++) {
 214                const char *arg = *argv++;
 215
 216                if (*arg == '-') {
 217                        /* Do flag handling here */
 218                        usage(receive_pack_usage);
 219                }
 220                if (dir)
 221                        usage(receive_pack_usage);
 222                dir = arg;
 223        }
 224        if (!dir)
 225                usage(receive_pack_usage);
 226
 227        /* chdir to the directory. If that fails, try appending ".git" */
 228        if (chdir(dir) < 0) {
 229                if (chdir(mkpath("%s.git", dir)) < 0)
 230                        die("unable to cd to %s", dir);
 231        }
 232
 233        /* If we have a ".git" directory, chdir to it */
 234        chdir(".git");
 235        setenv("GIT_DIR", ".", 1);
 236
 237        if (access("objects", X_OK) < 0 || access("refs/heads", X_OK) < 0)
 238                die("%s doesn't appear to be a git directory", dir);
 239        write_head_info();
 240
 241        /* EOF */
 242        packet_flush(1);
 243
 244        read_head_info();
 245        if (commands) {
 246                unpack();
 247                execute_commands();
 248        }
 249        return 0;
 250}