shallow: verify shallow file after taking lock
authorJeff King <peff@peff.net>
Sat, 15 Mar 2014 03:47:06 +0000 (23:47 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 17 Mar 2014 22:03:32 +0000 (15:03 -0700)
Before writing the shallow file, we stat() the existing file
to make sure it has not been updated since our operation
began. However, we do not do so under a lock, so there is a
possible race:

1. Process A takes the lock.

2. Process B calls check_shallow_file_for_update and finds
no update.

3. Process A commits the lockfile.

4. Process B takes the lock, then overwrite's process A's
changes.

We can fix this by doing our check while we hold the lock.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
shallow.c
index c7602ce3a2076f1ec0dfdfaee65a1810f45e5601..0b267b64117c5f1d2df662e3d413418d575a94bd 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -263,9 +263,9 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
        struct strbuf sb = STRBUF_INIT;
        int fd;
 
-       check_shallow_file_for_update();
        fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
                                       LOCK_DIE_ON_ERROR);
+       check_shallow_file_for_update();
        if (write_shallow_commits(&sb, 0, extra)) {
                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
                        die_errno("failed to write to %s",
@@ -310,9 +310,9 @@ void prune_shallow(int show_only)
                strbuf_release(&sb);
                return;
        }
-       check_shallow_file_for_update();
        fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
                                       LOCK_DIE_ON_ERROR);
+       check_shallow_file_for_update();
        if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
                if (write_in_full(fd, sb.buf, sb.len) != sb.len)
                        die_errno("failed to write to %s",