summaryrefslogtreecommitdiff
path: root/receive-pack.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-30 17:15:22 (GMT)
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-30 17:15:22 (GMT)
commit2eca23daf5ab7c921c544d86cd53707f8b4ff9a4 (patch)
tree0c35c6a306182c448b13ae24afe2fad169aaa58f /receive-pack.c
parent56b6ed8881f3504b686a254cccdb5aa1a1a9e925 (diff)
downloadgit-2eca23daf5ab7c921c544d86cd53707f8b4ff9a4.zip
git-2eca23daf5ab7c921c544d86cd53707f8b4ff9a4.tar.gz
git-2eca23daf5ab7c921c544d86cd53707f8b4ff9a4.tar.bz2
git-receive-pack: implement ref switch command handling
After unpacking the object pack successfully, we go through the list of refs, and verify that they still contain their expected values. Then we replace them with the new ones.
Diffstat (limited to 'receive-pack.c')
-rw-r--r--receive-pack.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/receive-pack.c b/receive-pack.c
index fb43107..7ce5f1e 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -77,6 +77,8 @@ static void write_head_info(const char *base, int nr, char **match)
}
if (read_ref(path, sha1) < 0)
continue;
+ if (!has_sha1_file(sha1))
+ continue;
if (nr && !path_match(path, nr, match))
continue;
show_ref(path, sha1);
@@ -95,6 +97,61 @@ struct command {
struct command *commands = NULL;
+static int verify_old_ref(const char *name, char *hex_contents)
+{
+ int fd, ret;
+ char buffer[60];
+
+ 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 void update(const char *name, unsigned char *old_sha1, unsigned char *new_sha1)
+{
+ char new_hex[60], *old_hex, *lock_name;
+ int newfd, namelen, written;
+
+ 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));
+ new_hex[40] = '\n';
+ new_hex[41] = 0;
+ old_hex = sha1_to_hex(old_sha1);
+ if (!has_sha1_file(new_sha1))
+ die("unpack should have generated %s, but I can't find it!", new_hex);
+
+ newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ if (newfd < 0)
+ die("unable to create %s (%s)", lock_name, strerror(errno));
+ written = write(newfd, new_hex, 41);
+ close(newfd);
+ if (written != 41) {
+ unlink(lock_name);
+ die("unable to write %s", lock_name);
+ }
+ if (verify_old_ref(name, old_hex) < 0) {
+ unlink(lock_name);
+ die("%s changed during push", name);
+ }
+ if (rename(lock_name, name) < 0) {
+ unlink(lock_name);
+ die("unable to replace %s", name);
+ }
+ fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
+}
+
+
/*
* This gets called after(if) we've successfully
* unpacked the data payload.
@@ -104,10 +161,7 @@ static void execute_commands(void)
struct command *cmd = commands;
while (cmd) {
- char old_hex[60], *new_hex;
- strcpy(old_hex, sha1_to_hex(cmd->old_sha1));
- new_hex = sha1_to_hex(cmd->new_sha1);
- fprintf(stderr, "%s: %s -> %s\n", cmd->ref_name, old_hex, new_hex);
+ update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
cmd = cmd->next;
}
}
@@ -149,7 +203,6 @@ static void unpack(void)
if (pid < 0)
die("unpack fork failed");
if (!pid) {
- setenv("GIT_DIR", ".", 1);
execlp(unpacker, unpacker, NULL);
die("unpack execute failed");
}
@@ -212,6 +265,7 @@ int main(int argc, char **argv)
/* If we have a ".git" directory, chdir to it */
chdir(".git");
+ setenv("GIT_DIR", ".", 1);
if (access("objects", X_OK) < 0 || access("refs/heads", X_OK) < 0)
die("%s doesn't appear to be a git directory", dir);