diff options
Diffstat (limited to 'receive-pack.c')
-rw-r--r-- | receive-pack.c | 340 |
1 files changed, 0 insertions, 340 deletions
diff --git a/receive-pack.c b/receive-pack.c deleted file mode 100644 index 93929b5371..0000000000 --- a/receive-pack.c +++ /dev/null @@ -1,340 +0,0 @@ -#include "cache.h" -#include "refs.h" -#include "pkt-line.h" -#include "run-command.h" -#include <sys/wait.h> - -static const char receive_pack_usage[] = "git-receive-pack <git-dir>"; - -static const char *unpacker[] = { "unpack-objects", NULL }; - -static int report_status = 0; - -static char capabilities[] = "report-status"; -static int capabilities_sent = 0; - -static int show_ref(const char *path, const unsigned char *sha1) -{ - if (capabilities_sent) - packet_write(1, "%s %s\n", sha1_to_hex(sha1), path); - else - packet_write(1, "%s %s%c%s\n", - sha1_to_hex(sha1), path, 0, capabilities); - capabilities_sent = 1; - return 0; -} - -static void write_head_info(void) -{ - for_each_ref(show_ref); - if (!capabilities_sent) - show_ref("capabilities^{}", null_sha1); - -} - -struct command { - struct command *next; - const char *error_string; - unsigned char old_sha1[20]; - unsigned char new_sha1[20]; - char ref_name[FLEX_ARRAY]; /* more */ -}; - -static struct command *commands = NULL; - -static int is_all_zeroes(const char *hex) -{ - int i; - for (i = 0; i < 40; i++) - if (*hex++ != '0') - return 0; - return 1; -} - -static int verify_old_ref(const char *name, char *hex_contents) -{ - int fd, ret; - char buffer[60]; - - if (is_all_zeroes(hex_contents)) - return 0; - fd = open(name, O_RDONLY); - if (fd < 0) - return -1; - ret = read(fd, buffer, 40); - close(fd); - if (ret != 40) - return -1; - if (memcmp(buffer, hex_contents, 40)) - return -1; - return 0; -} - -static char update_hook[] = "hooks/update"; - -static int run_update_hook(const char *refname, - char *old_hex, char *new_hex) -{ - int code; - - if (access(update_hook, X_OK) < 0) - return 0; - code = run_command(update_hook, refname, old_hex, new_hex, NULL); - switch (code) { - case 0: - return 0; - case -ERR_RUN_COMMAND_FORK: - return error("hook fork failed"); - case -ERR_RUN_COMMAND_EXEC: - return error("hook execute failed"); - case -ERR_RUN_COMMAND_WAITPID: - return error("waitpid failed"); - case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: - return error("waitpid is confused"); - case -ERR_RUN_COMMAND_WAITPID_SIGNAL: - return error("%s died of signal", update_hook); - case -ERR_RUN_COMMAND_WAITPID_NOEXIT: - return error("%s died strangely", update_hook); - default: - error("%s exited with error code %d", update_hook, -code); - return -code; - } -} - -static int update(struct command *cmd) -{ - const char *name = cmd->ref_name; - unsigned char *old_sha1 = cmd->old_sha1; - unsigned char *new_sha1 = cmd->new_sha1; - char new_hex[60], *old_hex, *lock_name; - int newfd, namelen, written; - - cmd->error_string = NULL; - if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) { - cmd->error_string = "funny refname"; - return error("refusing to create funny ref '%s' locally", - name); - } - - namelen = strlen(name); - lock_name = xmalloc(namelen + 10); - memcpy(lock_name, name, namelen); - memcpy(lock_name + namelen, ".lock", 6); - - strcpy(new_hex, sha1_to_hex(new_sha1)); - old_hex = sha1_to_hex(old_sha1); - if (!has_sha1_file(new_sha1)) { - cmd->error_string = "bad pack"; - return error("unpack should have generated %s, " - "but I can't find it!", new_hex); - } - safe_create_leading_directories(lock_name); - - newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666); - if (newfd < 0) { - cmd->error_string = "can't lock"; - return error("unable to create %s (%s)", - lock_name, strerror(errno)); - } - - /* Write the ref with an ending '\n' */ - new_hex[40] = '\n'; - new_hex[41] = 0; - written = write(newfd, new_hex, 41); - /* Remove the '\n' again */ - new_hex[40] = 0; - - close(newfd); - if (written != 41) { - unlink(lock_name); - cmd->error_string = "can't write"; - return error("unable to write %s", lock_name); - } - if (verify_old_ref(name, old_hex) < 0) { - unlink(lock_name); - cmd->error_string = "raced"; - return error("%s changed during push", name); - } - if (run_update_hook(name, old_hex, new_hex)) { - unlink(lock_name); - cmd->error_string = "hook declined"; - return error("hook declined to update %s", name); - } - else if (rename(lock_name, name) < 0) { - unlink(lock_name); - cmd->error_string = "can't rename"; - return error("unable to replace %s", name); - } - else { - fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex); - return 0; - } -} - -static char update_post_hook[] = "hooks/post-update"; - -static void run_update_post_hook(struct command *cmd) -{ - struct command *cmd_p; - int argc; - const char **argv; - - if (access(update_post_hook, X_OK) < 0) - return; - for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) { - if (cmd_p->error_string) - continue; - argc++; - } - argv = xmalloc(sizeof(*argv) * (1 + argc)); - argv[0] = update_post_hook; - - for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) { - char *p; - if (cmd_p->error_string) - continue; - p = xmalloc(strlen(cmd_p->ref_name) + 1); - strcpy(p, cmd_p->ref_name); - argv[argc] = p; - argc++; - } - argv[argc] = NULL; - run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO); -} - -/* - * This gets called after(if) we've successfully - * unpacked the data payload. - */ -static void execute_commands(void) -{ - struct command *cmd = commands; - - while (cmd) { - update(cmd); - cmd = cmd->next; - } - run_update_post_hook(commands); -} - -static void read_head_info(void) -{ - struct command **p = &commands; - for (;;) { - static char line[1000]; - unsigned char old_sha1[20], new_sha1[20]; - struct command *cmd; - char *refname; - int len, reflen; - - len = packet_read_line(0, line, sizeof(line)); - if (!len) - break; - if (line[len-1] == '\n') - line[--len] = 0; - if (len < 83 || - line[40] != ' ' || - line[81] != ' ' || - get_sha1_hex(line, old_sha1) || - get_sha1_hex(line + 41, new_sha1)) - die("protocol error: expected old/new/ref, got '%s'", - line); - - refname = line + 82; - reflen = strlen(refname); - if (reflen + 82 < len) { - if (strstr(refname + reflen + 1, "report-status")) - report_status = 1; - } - cmd = xmalloc(sizeof(struct command) + len - 80); - memcpy(cmd->old_sha1, old_sha1, 20); - memcpy(cmd->new_sha1, new_sha1, 20); - memcpy(cmd->ref_name, line + 82, len - 81); - cmd->error_string = "n/a (unpacker error)"; - cmd->next = NULL; - *p = cmd; - p = &cmd->next; - } -} - -static const char *unpack(int *error_code) -{ - int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD); - - *error_code = 0; - switch (code) { - case 0: - return NULL; - case -ERR_RUN_COMMAND_FORK: - return "unpack fork failed"; - case -ERR_RUN_COMMAND_EXEC: - return "unpack execute failed"; - case -ERR_RUN_COMMAND_WAITPID: - return "waitpid failed"; - case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: - return "waitpid is confused"; - case -ERR_RUN_COMMAND_WAITPID_SIGNAL: - return "unpacker died of signal"; - case -ERR_RUN_COMMAND_WAITPID_NOEXIT: - return "unpacker died strangely"; - default: - *error_code = -code; - return "unpacker exited with error code"; - } -} - -static void report(const char *unpack_status) -{ - struct command *cmd; - packet_write(1, "unpack %s\n", - unpack_status ? unpack_status : "ok"); - for (cmd = commands; cmd; cmd = cmd->next) { - if (!cmd->error_string) - packet_write(1, "ok %s\n", - cmd->ref_name); - else - packet_write(1, "ng %s %s\n", - cmd->ref_name, cmd->error_string); - } - packet_flush(1); -} - -int main(int argc, char **argv) -{ - int i; - char *dir = NULL; - - argv++; - for (i = 1; i < argc; i++) { - char *arg = *argv++; - - if (*arg == '-') { - /* Do flag handling here */ - usage(receive_pack_usage); - } - if (dir) - usage(receive_pack_usage); - dir = arg; - } - if (!dir) - usage(receive_pack_usage); - - if(!enter_repo(dir, 0)) - die("'%s': unable to chdir or not a git archive", dir); - - write_head_info(); - - /* EOF */ - packet_flush(1); - - read_head_info(); - if (commands) { - int code; - const char *unpack_status = unpack(&code); - if (!unpack_status) - execute_commands(); - if (report_status) - report(unpack_status); - } - return 0; -} |