diff options
author | Nicolas Pitre <nico@cam.org> | 2006-11-01 17:06:25 -0500 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-11-03 00:24:07 -0800 |
commit | 576162a45f35e157427300066b0ff566ff698a0f (patch) | |
tree | 2fdc7abe3ac1688b340b30cffd7d5e086c04998f /receive-pack.c | |
parent | 9ca4a201eaf0c58dbc7184cb2d5ab01c48cb7447 (diff) | |
download | git-576162a45f35e157427300066b0ff566ff698a0f.tar.gz |
remove .keep pack lock files when done with refs update
This makes both git-fetch and git-push (fetch-pack and receive-pack)
safe against a possible race with aparallel git-repack -a -d that could
prune the new pack while it is not yet referenced, and remove the .keep
file after refs have been updated.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'receive-pack.c')
-rw-r--r-- | receive-pack.c | 96 |
1 files changed, 73 insertions, 23 deletions
diff --git a/receive-pack.c b/receive-pack.c index b8d12700d8..d56898c9b2 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -3,8 +3,10 @@ #include "refs.h" #include "pkt-line.h" #include "run-command.h" +#include "exec_cmd.h" #include "commit.h" #include "object.h" +#include <sys/wait.h> static const char receive_pack_usage[] = "git-receive-pack <git-dir>"; @@ -251,12 +253,13 @@ static const char *parse_pack_header(struct pack_header *hdr) return NULL; } +static const char *pack_lockfile; + static const char *unpack(void) { struct pack_header hdr; const char *hdr_err; char hdr_arg[38]; - int code; hdr_err = parse_pack_header(&hdr); if (hdr_err) @@ -265,33 +268,13 @@ static const char *unpack(void) ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { + int code; const char *unpacker[3]; unpacker[0] = "unpack-objects"; unpacker[1] = hdr_arg; unpacker[2] = NULL; code = run_command_v_opt(1, unpacker, RUN_GIT_CMD); - } else { - const char *keeper[6]; - char my_host[255], keep_arg[128 + 255]; - - if (gethostname(my_host, sizeof(my_host))) - strcpy(my_host, "localhost"); - snprintf(keep_arg, sizeof(keep_arg), - "--keep=receive-pack %i on %s", - getpid(), my_host); - - keeper[0] = "index-pack"; - keeper[1] = "--stdin"; - keeper[2] = "--fix-thin"; - keeper[3] = hdr_arg; - keeper[4] = keep_arg; - keeper[5] = NULL; - code = run_command_v_opt(1, keeper, RUN_GIT_CMD); - if (!code) - reprepare_packed_git(); - } - - switch (code) { + switch (code) { case 0: return NULL; case -ERR_RUN_COMMAND_FORK: @@ -308,6 +291,71 @@ static const char *unpack(void) return "unpacker died strangely"; default: return "unpacker exited with error code"; + } + } else { + const char *keeper[6]; + int fd[2], s, len, status; + pid_t pid; + char keep_arg[256]; + char packname[46]; + + s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid()); + if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) + strcpy(keep_arg + s, "localhost"); + + keeper[0] = "index-pack"; + keeper[1] = "--stdin"; + keeper[2] = "--fix-thin"; + keeper[3] = hdr_arg; + keeper[4] = keep_arg; + keeper[5] = NULL; + + if (pipe(fd) < 0) + return "index-pack pipe failed"; + pid = fork(); + if (pid < 0) + return "index-pack fork failed"; + if (!pid) { + dup2(fd[1], 1); + close(fd[1]); + close(fd[0]); + execv_git_cmd(keeper); + die("execv of index-pack failed"); + } + close(fd[1]); + + /* + * The first thing we expects from index-pack's output + * is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where + * %40s is the newly created pack SHA1 name. In the "keep" + * case, we need it to remove the corresponding .keep file + * later on. If we don't get that then tough luck with it. + */ + for (len = 0; + len < 46 && (s = xread(fd[0], packname+len, 46-len)) > 0; + len += s); + close(fd[0]); + if (len == 46 && packname[45] == '\n' && + memcmp(packname, "keep\t", 5) == 0) { + char path[PATH_MAX]; + packname[45] = 0; + snprintf(path, sizeof(path), "%s/pack/pack-%s.keep", + get_object_directory(), packname + 5); + pack_lockfile = xstrdup(path); + } + + /* Then wrap our index-pack process. */ + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + return "waitpid failed"; + if (WIFEXITED(status)) { + int code = WEXITSTATUS(status); + if (code) + return "index-pack exited with error code"; + reprepare_packed_git(); + return NULL; + } + return "index-pack abnormal exit"; } } @@ -363,6 +411,8 @@ int main(int argc, char **argv) const char *unpack_status = unpack(); if (!unpack_status) execute_commands(); + if (pack_lockfile) + unlink(pack_lockfile); if (report_status) report(unpack_status); } |