]> source.dussan.org Git - jgit.git/commitdiff
FS.detectSymlinkSupport: fix a race 54/1174154/4
authorMotiejus Jakštys <motiejus@jakstys.lt>
Thu, 28 Dec 2023 14:33:28 +0000 (16:33 +0200)
committerMatthias Sohn <matthias.sohn@sap.com>
Mon, 19 Feb 2024 23:16:00 +0000 (23:16 +0000)
When multiple JGit clients are instantiated concurrently, they may try
to create the same symlink at the same time. When that happens, the
second thread will return an error (because the symlink already exists)
and that `FS` instance will think that symlinks are not supported,
causing havoc.

Change-Id: I362b933ff63a1471e3a5d70cc8c35eb2f25cc0dd
Signed-off-by: Motiejus Jakštys <motiejus@jakstys.lt>
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java

index 51236e1cc03dc0aae0aae095243077d79c2928c4..3a7fa2388ecf3469490ec0b9132c6e3cf87215c6 100644 (file)
@@ -29,8 +29,12 @@ import java.nio.file.attribute.PosixFilePermission;
 import java.time.Duration;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jgit.errors.CommandFailedException;
@@ -195,6 +199,23 @@ public class FSTest {
                                  SystemReader.getInstance().getDefaultCharset().name());
        }
 
+       @Test
+       @SuppressWarnings("boxing")
+       public void testConcurrentSymlinkSupport()
+                       throws ExecutionException, InterruptedException {
+               Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+               int n = 3;
+               List<CompletableFuture<Boolean>> futures = new ArrayList<>();
+               for (int i = 0; i < n; i++) {
+                       futures.add(CompletableFuture.supplyAsync(
+                                       () -> FS.DETECTED.newInstance().supportsSymlinks()));
+               }
+
+               for (int i = 0; i < n; i++) {
+                       assertTrue(futures.get(i).get());
+               }
+       }
+
        @Test
        public void testFsTimestampResolution() throws Exception {
                DateTimeFormatter formatter = DateTimeFormatter
index ac973a9c1d849c7ed7ecb912487321073401d9cf..a8e1dae10e76fcc151de777f12ceabf33e1205bd 100644 (file)
@@ -1024,7 +1024,7 @@ public abstract class FS {
                File tempFile = null;
                try {
                        tempFile = File.createTempFile("tempsymlinktarget", ""); //$NON-NLS-1$ //$NON-NLS-2$
-                       File linkName = new File(tempFile.getParentFile(), "tempsymlink"); //$NON-NLS-1$
+                       File linkName = new File(tempFile.getPath() + "-tempsymlink"); //$NON-NLS-1$
                        createSymLink(linkName, tempFile.getPath());
                        supportSymlinks = Boolean.TRUE;
                        linkName.delete();