]> git.ipfire.org Git - thirdparty/git.git/commitdiff
run-command: invalidate lstat cache after a command finished
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Tue, 2 Feb 2021 21:09:52 +0000 (22:09 +0100)
committerJohannes Schindelin <johannes.schindelin@gmx.de>
Fri, 12 Feb 2021 14:47:02 +0000 (15:47 +0100)
In the previous commit, we intercepted calls to `rmdir()` to invalidate
the lstat cache in the successful case, so that the lstat cache could
not have the idea that a directory exists where there is none.

The same situation can arise, of course, when a separate process is
spawned (most notably, this is the case in `submodule_move_head()`).
Obviously, we cannot know whether a directory was removed in that
process, therefore we must invalidate the lstat cache afterwards.

Note: in contrast to `lstat_cache_aware_rmdir()`, we invalidate the
lstat cache even in case of an error: the process might have removed a
directory and still have failed afterwards.

Co-authored-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
run-command.c
t/t0021-conversion.sh

index a483d5904a3ec1acae8908dd2e699fa00bcaaa9d..c5c4d366715e101fd777600fece4d4c474bc71ba 100644 (file)
@@ -953,6 +953,7 @@ int finish_command(struct child_process *cmd)
 {
        int ret = wait_or_whine(cmd->pid, cmd->argv[0], 0);
        child_process_clear(cmd);
+       invalidate_lstat_cache();
        return ret;
 }
 
@@ -1239,13 +1240,19 @@ error:
 int finish_async(struct async *async)
 {
 #ifdef NO_PTHREADS
-       return wait_or_whine(async->pid, "child process", 0);
+       int ret = wait_or_whine(async->pid, "child process", 0);
+
+       invalidate_lstat_cache();
+
+       return ret;
 #else
        void *ret = (void *)(intptr_t)(-1);
 
        if (pthread_join(async->tid, &ret))
                error("pthread_join failed");
+       invalidate_lstat_cache();
        return (int)(intptr_t)ret;
+
 #endif
 }
 
index 8ff917fca6d9fe090120e6c07a34151c8717bdcb..a714d376a38ed892d62fc6a17b3b2ded8132e5ca 100755 (executable)
@@ -862,4 +862,40 @@ do
        '
 done
 
+test_expect_success PERL,SYMLINKS,CASE_INSENSITIVE_FS \
+"delayed checkout with submodule collision don't write to the wrong place" '
+       git init collision-with-submodule &&
+       (
+               cd collision-with-submodule &&
+               git config filter.delay.process "\"$TEST_ROOT/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
+               git config filter.delay.required true &&
+
+               # We need Git to treat the submodule "a" and the
+               # leading dir "A" as different paths in the index.
+               git config --local core.ignoreCase false &&
+
+               empty_oid=$(printf "" | git hash-object -w --stdin) &&
+               attr_oid=$(echo "A/B/y filter=delay" | git hash-object -w --stdin) &&
+               cat >objs <<-EOF &&
+               100644 blob $empty_oid  A/B/x
+               100644 blob $empty_oid  A/B/y
+               100644 blob $attr_oid   .gitattributes
+               EOF
+               git update-index --index-info <objs &&
+
+               git init a &&
+               mkdir target-dir &&
+               symlink_oid=$(printf "%s" "$PWD/target-dir" | git -C a hash-object -w --stdin) &&
+               echo "120000 blob $symlink_oid  b" >objs &&
+               git -C a update-index --index-info <objs &&
+               git -C a commit -m sub &&
+               git submodule add ./a &&
+               git commit -m super &&
+
+               git checkout --recurse-submodules . &&
+               grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log &&
+               test_path_is_missing target-dir/y
+       )
+'
+
 test_done